Wîkîferheng
kuwiktionary
https://ku.wiktionary.org/wiki/Destp%C3%AAk
MediaWiki 1.47.0-wmf.10
case-sensitive
Medya
Taybet
Gotûbêj
Bikarhêner
Gotûbêja bikarhêner
Wîkîferheng
Gotûbêja Wîkîferhengê
Wêne
Gotûbêja wêneyî
MediaWiki
Gotûbêja MediaWiki
Şablon
Gotûbêja şablonê
Alîkarî
Gotûbêja alîkariyê
Kategorî
Gotûbêja kategoriyê
Pêvek
Gotûbêja pêvekê
Nimînok
Gotûbêja nimînokê
Portal
Gotûbêja portalê
Tewandin
Gotûbêja tewandinê
Jinûvesazî
Gotûbêja jinûvesaziyê
TimedText
TimedText talk
Modul
Gotûbêja modulê
Event
Event talk
reş
0
3121
6241660
6233912
2026-07-11T20:22:57Z
Wikihez
7344
[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin
6241660
wikitext
text/x-wiki
{{bnr-h|res}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-reş.wav|Deng|Wan}}
* {{ku-kîte}}
=== Rengdêr ===
{{ku-tewîn-rd|reş}}
[[Wêne:Solid black.svg|thumb|150px|Rengê reş.]]
{{rengdêr|ku}}
# {{f|ku|reng}} [[reng|Reng]]ê ji hemiyan [[tarî]]tir, [[wek]] rengê [[rejî|rejiyê]].
#: {{panela rengê|000000}}
#* {{jêder|ku|jêgirtin=-Tu jî mîna Fêdkayê min esmer î, çevreş, porê te '''reş'''.|{{Jêgirtin/Frîda Hecî Cewarî/Bîranînên Min}}}}
#* {{jêder|ku|jêgirtin=Digel ku emrê wî hê sî û pênc bû jî tayekî '''reş''' di porê wî de nemabû.|{{Jêgirtin/Firat Cewerî/Kevoka Spî/1996}}}}
#* {{jêder|ku|jêgirtin=Û ew libasêd '''reş''' heta şeş mehan û yaxo salekê li ser ehlê (xizmê) meyyitî dimînin. Ew ehlê meyyitî heta ji şînê bidernekevin naçine dawet û kêfxweşiyan.|{{jêgirtin/Mele Mehmûdê Bayezîdî/Adat û Rusûmatnameê Ekradiye|r=53}}}}
# Ji [[ronahî|ronahiyê]] [[bêpar]].
#: {{hevmane|ku|tarî}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Saqî ko dêm mehweş bitin<br />Kagul ji şêva '''reş''' bitin<br />Qerqef bila ateş bitin}}
#* {{jêder|ku|jêgirtin=(...) mîna tîrekê navdilê Qaçax hingavtin, ling lê lerizîn, ber çavên wî '''reş''' bû (...)|{{Jêgirtin/Sîma Semend/Xezal/1996}}}}
# [[temirandî]]
#: {{nm|ku|Ka wê çirayê '''reş''' bike.}}
# [[mirov|Mirov]]ên [[çerm]]reş yên mîna [[Afrîkî|afrîkiyan]].
#: {{hevmane|ku|çermreş}}
#* {{jêder|ku|jêgirtin=Zelamekê req û hişk û '''reş''' hate bi nik wan ve.|{{Jêgirtin/Xelîl Duhokî/Antolojiya Çîroka Nû ya Kurmancên Başûr}}}}
# [[bêyom]], [[pirr]] [[xirab]], [[nebaş]]
#* {{jêder|ku|jêgirtin=Bextê me '''reş''' e, kezeb birîn e.|{{Jêgirtin/Mehmed Uzun/Siya Evînê/1989}}}}
==== Bi alfabeyên din ====
* {{ku-ar|ڕەش}}
* {{ku-kr|рәш}}
==== Herwiha ====
* {{hw|ku|riş||Reşwî}}
==== Hevmane ====
* {{g|ku|siyah}} {{i|tenê [[edebî]]}}
* {{g|ku|qere-}} {{i|tenê wek [[pêşgir]]}}
==== Binêre herwiha ====
* {{g|ku|kesk}}
* {{g|ku|mor}}
* [[pembeyî]], [[pîvazî]]
* {{g|ku|pirteqalî}}
* {{g|ku|qehweyî}}
* {{g|ku|sor}}
* {{g|ku|şîn}}
* {{g|ku|zer}}
==== Jê ====
{{stûn|
* {{mj|lêker}} {{g|ku|reş bûn}}
* {{mj|lêker}} {{g|ku|reş kirin}}
* {{mj|navdêr}} {{g|ku|reşbûn}}
* {{mj|navdêr}} {{g|ku|reşkirin}}
* {{mj|rengdêr}} {{g|ku|reşbûyî}}
* {{mj|rengdêr}} {{g|ku|reşkirî}}
* {{g|ku|reşokî}}
* {{g|ku|reşole}}
* {{g|ku|reşnivîs}}
* {{g|ku|reşmeh}}
* {{g|ku|reşname}}
* {{g|ku|reşpatî}}
* {{g|ku|ripîreş}}
}}
==== Etîmolojî ====
Taliyê ji {{ji|ira-pro|ku|*ra(n)ǰ-|w=reng kirin, boyax kirin}}.
Hevreha {{hv|ckb|ڕەش}}, {{hv|kho|rraşa|w=ya ku bi rengê tarî}}, {{hv|tly|رش|tr=rəş|w=qehweyiya zelal}}, {{hv|sog|tr=rɣš-|ts=raxš|w={{w|Rexş}}, hespê [[Ristem]]}}, {{hv|fa|رخش|tr=rexş|w=sor}}, {{hv|mzn|رش|tr=raš|w=sor}}. Guherîna maneya rengan di zimanên hindûewropî de diyardeyeke berbelav e.
;{{biçûk|Çavkanî:
* {{Cheung|r=314}}
}}
==== Bide ber ====
* {{g|ku|reştarî}}
* {{g|ku|reşûşîn kirin}}
* {{g|ku|reşûşîn}}
* {{g|ku|reşpoş}}
==== Bi zaravayên din ====
* {{Z|ckb}}: {{W-|ckb|ڕەش|tr=reş}}
* {{Z|sdh}}: {{W-|sdh|siya|sc=Latn}}, {{W-|sdh|siyaw|sc=Latn}}
* {{Z|hac}}: {{W-|hac|siyaw|sc=Latn}}
* {{Z|zza}}: {{W-|zza|sîya}}
==== Werger ====
{{werger-ser}}
* {{Z|ab}}: {{W-|ab|аиқәаҵәа}}
* {{Z|ace}}: {{W-|ace|itam}}
* {{Z|adt}}: {{W-|adt|waurrunha}}
* {{Z|af}}: {{W+|af|swart}}
* {{Z|akl}}: {{W-|akl|maitum}}
* {{Z|sq}}: {{W+|sq|zi}}
* {{Z|de}}: {{W+|de|schwarz}}
* {{Z|alt}}: {{W-|alt|кара}}
* {{Z|am}}: {{W-|am|ጥቁር}}
* {{Z|ani}}: {{W-|ani|бечӏедир}}
* {{Z|rme}}: {{W-|rme|kalo}}
* Apaçî:
*: {{Z|apw}}: {{W-|apw|diłhił}}
* {{Z|an}}: {{W-|an|negro}}
* {{Z|rup}}: {{W-|rup|negru}}, {{W+|rup|laiu}}
* {{Z|aer}}: {{W-|aer|artepe}}
* {{Z|as}}: {{W-|as|ক’লা}}, {{W-|as|কুলা}}
* {{Z|ast}}: {{W+|ast|ñegru}}, {{W+|ast|negru}}, {{W+|ast|prietu}}
* {{Z|cni}}: {{W-|cni|cheenkari}}, {{W-|cni|kisaari}}
* {{Z|atj}}: {{W-|atj|makatewaw}}
* {{Z|aot}}: {{W-|aot|pinak}}
* {{Z|av}}: {{W-|av|чӏегӏера}}, {{W-|av|чӏегӏераб}}
* {{Z|ay}}: {{W-|ay|ch’iyara}}
* {{Z|az}}: {{W+|az|qara}}
* {{Z|ban}}: {{W-|ban|badeng}}
* {{Z|bjn}}: {{W-|bjn|hirang}}
* {{Z|eu}}: {{W-|eu|beltz}}
* {{Z|ba}}: {{W-|ba|ҡара}}
* {{Z|bbl}}: {{W-|bbl|ჺარჭინ}}
* {{Z|be}}: {{W+|be|чо́рны}}
* {{Z|bn}}: {{W+|bn|কালো}}, {{W+|bn|কাল}}
* {{Z|br}}: {{W+|br|du}}
* {{Z|bug}}: {{W-|bug|ma-lotoŋ}}
* {{Z|mbb}}: {{W-|mbb|me'item}}
* {{Z|bg}}: {{W+|bg|че́рен}}
* {{Z|my}}: {{W+|my|နက်}}, {{W+|my|မည်း}}
* {{Z|bua}}: {{W-|bua|хара}}
* {{Z|kac}}: {{W-|kac|chyang}}
* {{Z|dz}}: {{W-|dz|གནགཔོ}}
* {{Z|ccc}}: {{W-|ccc|kosewa}}
* {{Z|ce}}: {{W-|ce|ӏаьржа}}
* {{Z|cs}}: {{W+|cs|černý}}
* {{Z|chr}}: {{W-|chr|ᎬᎿᎨ}}
* {{Z|cic}}: {{W-|cic|losa'}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|黑|tr=hak1}}, {{W-|yue|黑色|tr=haak1 sik1, hak1 sik1}}
*: {{Z|dng}}: {{W-|dng|хи}}
*: {{Z|cmn}}: {{W+|cmn|黑|tr=hēi}}, {{W+|cmn|黑色|tr=hēisè}}, {{W+|cmn|烏色|tr=wūsè}}
*: {{Z|cdo}}: {{W-|cdo|烏|tr=ŭ}}
*: {{Z|nan}}: {{W-|nan|黑|tr=hek}}, {{W-|nan|黑色|tr=hek-sek}}, {{W+|nan|烏色|tr=o͘-siak / o͘-sek}}
*: {{Z|wuu}}: {{W-|wuu|黑}}
* {{Z|cv}}: {{W-|cv|хура}}
* {{Z|chk}}: {{W-|chk|chon}}
* {{Z|dlm}}: {{W-|dlm|fosc}}
* {{Z|da}}: {{W+|da|sort}}
* {{Z|dgr}}: {{W-|dgr|dezǫ}}
* {{Z|dlg}}: {{W-|dlg|кара}}
* {{Z|ovd}}: {{W-|ovd|swart}}
* {{Z|id}}: {{W+|id|hitam}}
* {{Z|ar}}: {{W+|ar|أَسْوَد|n}}, {{W-|ar|سَوْدَاء|m}}, {{W-|ar|سُود|p}}
*: {{Z|arz}}: {{W-|arz|اسود|tr=eswid}}
*: {{Z|acw}}: {{W-|acw|أسود|tr=ʾaswad}}
*: {{Z|ary}}: {{W-|ary|كحل|tr=kḥal}}, {{W-|ary|سود|tr=swad}}
* {{Z|hy}}: {{W-|hy|սև}}
* {{Z|myv}}: {{W-|myv|раужо}}
* {{Z|eo}}: {{W+|eo|nigra}}
* {{Z|et}}: {{W+|et|must}}
* {{Z|ett}}: {{W-|ett|𐌑𐌖𐌓𐌉}}
* {{Z|eve}}: {{W-|eve|хакарин}}
* {{Z|evn}}: {{W-|evn|конңорин}}
* {{Z|ee}}: {{W-|ee|yibɔ}}
* {{Z|ext}}: {{W-|ext|negru}}
* {{Z|fa}}: {{W+|fa|سیاه|tr=siyâh}}
* {{Z|fo}}: {{W+|fo|svartur}}
* {{Z|fj}}: {{W+|fj|loaloa}}
* {{Z|fi}}: {{W+|fi|musta}}
* {{Z|fr}}: {{W+|fr|noir}}
* {{Z|fur}}: {{W-|fur|neri}}
* {{Z|frr}}:
*: Föhr: {{W-|frr|suart}}
*: Hallig: {{W-|frr|süürt}}
*: {{Z|frr}}: {{W-|frr|suurt}}
* {{Z|fy}}: {{W+|fy|swart}}
* {{Z|gd}}: {{W+|gd|dubh}}
* {{Z|gl}}: {{W+|gl|negro}}
* {{Z|gdo}}: {{W-|gdo|бечӏер}}
* {{Z|gon}}: {{W-|gon|నల్లా|tr=nallā}}
* {{Z|gor}}: {{W-|gor|yitomo}}
* {{Z|got}}: {{W-|got|𐍃𐍅𐌰𐍂𐍄𐍃}}
* {{Z|gu}}: {{W+|gu|કાળું}}
* {{Z|ka}}: {{W+|ka|შავი}}
* {{Z|ht}}: {{W-|ht|nwa}}
* {{Z|hur}}: {{W-|hur|ts'q'éyx̱}}
*: {{Z|hur}}: {{W-|hur|tsq'ix}}
* {{Z|haw}}: {{W-|haw|ʻeleʻele}}
* {{Z|mba}}: {{W-|mba|maitum}}
* {{Z|hi}}: {{W+|hi|काला}}, {{W+|hi|कारौ}}
* {{Z|hil}}: {{W-|hil|maitum}}
* {{Z|mww}}: {{W-|mww|dub}}
* {{Z|nl}}: {{W+|nl|zwart}}
* {{Z|hop}}: {{W-|hop|qömvi}}
* {{Z|ibg}}: {{W-|ibg|ngisit}}
* {{Z|he}}: {{W+|he|שחור|tr=shakhór|cuda=שחור \ שָׁחֹר}}, {{W-|he|שחורה|m|tr=sh'khorá|cuda=שחורה \ שְׁחֹרָה}}
* {{Z|io}}: {{W+|io|nigra}}
* {{Z|ig}}: {{W-|ig|nwa}}
* {{Z|ilo}}: {{W-|ilo|nangisit}}
* {{Z|ang}}: {{W-|ang|blæc}}, {{W-|ang|sweart}}
* {{Z|en}}: {{W+|en|black}}
* {{Z|inh}}: {{W-|inh|ӏаьржа}}
* {{Z|ia}}: {{W+|ia|nigre}}
* {{Z|ill}}: {{W-|ill|maitem}}
* {{Z|ga}}: {{W+|ga|dubh}}
* {{Z|isd}}: {{W-|isd|ngisit}}
* {{Z|ist}}: {{W-|ist|nìgaro}}, {{W-|ist|nìgro}}
* {{Z|it}}: {{W+|it|nero}}
* {{Z|ium}}: {{W-|ium|jieqv}}
* {{Z|is}}: {{W+|is|svartur}}
* {{Z|ja}}: {{W+|ja|黒い|tr=くろい, kuroi}}, {{W-|ja|[[黒色]]の|tr=こくしょくの, kokushoku no}}
* {{Z|jv}}: {{W+|jv|ireng}}, {{W-|jv|ireŋ}}, {{W-|jv|cemeŋ}}, {{W-|jv|hirěng}}
* {{Z|kl}}: {{W+|kl|qernertoq}}
* {{Z|xal}}: {{W-|xal|хар}}
* {{Z|kn}}: {{W+|kn|ಕಪ್ಪು}}
* {{Z|pam}}: {{W-|pam|matuling}}
* {{Z|krc}}: {{W-|krc|къара|tr=qara}}
* {{Z|csb}}: {{W-|csb|czôrny}}
* {{Z|ca}}: {{W+|ca|negre}}
* {{Z|zku}}: {{W-|zku|pulyuna}}
* {{Z|qu}}: {{W-|qu|yana}}
* {{Z|kjj}}: {{W-|kjj|мичӏаь}}
* {{Z|ky}}: {{W+|ky|кара}}, {{W-|ky|күңүрт кара}}, {{W+|ky|караңгы}}, {{W+|ky|каралоо}}, {{W+|ky|ушактоо}}, {{W+|ky|жамандоо}}, {{W+|ky|жаманатты кылуу}}, {{W+|ky|жала жабуу}}, {{W+|ky|көө}}
* {{Z|kg}}: {{W-|kg|ndombe}}
* {{Z|ki}}: {{W-|ki|-irũ}}
* {{Z|si}}: {{W+|si|කළු}}
* {{Z|koi}}: {{W-|koi|сьӧд}}
* {{Z|ko}}: {{W+|ko|검다}}, {{W+|ko|검은}}, {{W+|ko|까맣다}}, {{W-|ko|까만}}
* {{Z|kw}}: {{W-|kw|du}}
* {{Z|co}}: {{W+|co|neru}}
* {{Z|mfe}}: {{W-|mfe|nwar}}
* {{Z|kum}}: {{W-|kum|къара|tr=qara}}
* {{Z|qui}}: {{W-|qui|shĺpa}}
* {{Z|lbj}}: {{W-|lbj|ནག་པོ}}
* {{Z|lld}}: {{W-|lld|fosch|n}}
* {{Z|lad}}: {{W-|lad|preto}}
* {{Z|lkt}}: {{W-|lkt|sápa}}
* {{Z|ltg}}: {{W-|ltg|malns}}
* {{Z|la}}: {{W+|la|ater}}, {{W+|la|niger}}
* {{Z|lv}}: {{W+|lv|melns}}
* {{Z|lo}}: {{W-|lo|ດຳ}}
* {{Z|lez}}: {{W-|lez|чӏулав}}
* {{Z|mhx}}: {{W-|mhx|no, |tr=nòʔ}}
* {{Z|ln}}: {{W-|ln|moíndo}}
* {{Z|lij}}: {{W-|lij|néigro}}
* {{Z|li}}: {{W+|li|zwart}}
* {{Z|lt}}: {{W-|lt|júodas}}
* {{Z|lmo}}: {{W-|lmo|négher}}, {{W-|lmo|negro}}
* {{Z|khb}}: {{W-|khb|ᦡᧄ}}
* {{Z|mhn}}: {{W-|mhn|schbòrz}}
* {{Z|mad}}: {{W-|mad|celleng}}
* {{Z|mak}}: {{W-|mak|le'leng}}
* {{Z|mk}}: {{W-|mk|црн}}
* {{Z|mg}}: {{W+|mg|mainty}}
* {{Z|ml}}: {{W+|ml|കറുപ്പ്}}
* {{Z|ms}}: {{W+|ms|hitam}}, {{W+|ms|aswad}}, {{W-|ms|lotong}}, {{W-|ms|lutung}}, {{W-|ms|lutong}}
*: {{Z|ms}}: {{W-|ms|هيتم}}, {{W-|ms|اسود}}, {{W-|ms|لوتوڠ}}
* {{Z|mt}}: {{W+|mt|iswed|n}}, {{W-|mt|sewda|m}}, {{W-|mt|suwed|p}}
* {{Z|mnc}}: {{W-|mnc|ᠰᠠᡥᠠᠯᡳᠶᠠᠨ}}, {{W-|mnc|ᡴᠠᡵᠠ|tr=kara}}
* {{Z|gv}}: {{W-|gv|doo}}
* {{Z|msk}}: {{W-|msk|maitum}}
* {{Z|mi}}: {{W+|mi|mangu}}
* {{Z|mrw}}: {{W-|mrw|maitem}}, {{W-|mrw|delem}}
* {{Z|mr}}: {{W+|mr|काळा|n}}
* {{Z|mrc}}: {{W-|mrc|nilyig}}
* {{Z|mop}}: {{W-|mop|bʼox}}
* {{Z|hu}}: {{W+|hu|fekete}}
* {{Z|egy}}: {{W-egy|km|h=km-m-D3}}
* {{Z|lus}}: {{W-|lus|dum}}
* {{Z|min}}: {{W-|min|itam}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|хар}}
*: Mongolî: {{W-|mn|ᠬᠠᠷᠠ}}
* {{Z|nfr}}: {{W-|nfr|wɔɔ}}
* Nahuatl:
*: {{Z|nhn}}: {{W-|nhn|tliltic}}
*: Klasîk: {{W-|nci|tliltic}}, {{W-|nci|capotztic}}
* {{Z|naq}}: {{W-|naq|ǂnū}}
* {{Z|nmb}}: {{W-|nmb|im'ət}}
* {{Z|gld}}: {{W-|gld|сахарин}}
* {{Z|nap}}: {{W-|nap|niro}}
* {{Z|nv}}: {{W-|nv|łizhin}}
* {{Z|na}}: {{W+|na|etangang}}, {{W-|na|etañañ}}, {{W-|na|etaŋaŋ}}
* {{Z|nxq}}: {{W-|nxq|naq}}
* {{Z|nds}}:
*: {{Z|nds-de}}: {{W-|nds-de|swart}}
* {{Z|ne}}: {{W+|ne|कालो}}
* {{Z|nay}}: {{W-|nay|kro:tin}}
* {{Z|nia}}: {{W-|nia|a-itö}}
* {{Z|nog}}: {{W-|nog|кара}}
* {{Z|nuk}}: {{W-|nuk|tupkuk}}
* {{Z|nrf}}: {{W-|nrf|nièr|n}}, {{W-|nrf|né|n}}, {{W-|nrf|néthe|m}}, {{W-|nrf|naithe|m}}
* {{Z|non}}: {{W-|non|svartr}}, {{W-|non|blakkr}}
* {{Z|no}}: {{W+|no|svart}}, {{W+|no|sort}}
* {{Z|nwy}}: {{W-|nwy|gahuntee}}
* {{Z|ood}}: {{W-|ood|chuk}}
* {{Z|oj}}: {{W-|oj|makade-}}, {{W-|oj|makadewaa}}, {{W-|oj|makadewizi}}
* {{Z|oc}}: {{W+|oc|negre}}
* {{Z|or}}: {{W+|or|କଲା}}
* {{Z|om}}: {{W+|om|gurraacha}}
* {{Z|os}}: {{W-|os|сау}}
* {{Z|ug}}: {{W+|ug|قارا}}
* {{Z|uz}}: {{W+|uz|qora}}, {{W+|uz|siyoh}}
* {{Z|pag}}: {{W-|pag|deket}}
* {{Z|ps}}: {{W+|ps|تور}}
* {{Z|pms}}: {{W-|pms|neir}}
* {{Z|pjt}}: {{W-|pjt|maṟu}}
* {{Z|pl}}: {{W+|pl|czarny}}
* {{Z|pt}}: {{W+|pt|preto}}, {{W+|pt|atro}}, {{W+|pt|negro}}
* {{Z|pa}}: {{W+|pa|ਕਾਲਾ}}
* {{Z|kk}}: {{W+|kk|қара}}
* {{Z|cop}}: {{W-|cop|ⲭⲁⲙⲉ}}
* {{Z|rap}}: {{W-|rap|kere kere}}, {{W-|rap|uri uri}}
* {{Z|rhg}}: {{W-|rhg|hala}}
* {{Z|rgn}}: {{W-|rgn|négar}}
* {{Z|rm}}: {{W-|rm|nair}}
* {{Z|rom}}: {{W-|rom|kalo}}
*: {{Z|rmn}}: {{W-|rmn|kalo}}
*: {{Z|rml}}: {{W-|rml|kalo}}
*: {{Z|rmc}}: {{W-|rmc|kalo}}
*: {{Z|rmo}}: {{W-|rmo|kalo}}
*: {{Z|rmy}}: {{W-|rmy|kalo}}
* {{Z|ro}}: {{W+|ro|negru}}
* {{Z|ru}}: {{W+|ru|чёрный}}, {{W+|ru|вороно́й}}
* {{Z|str}}: {{W-|str|NEKIX}}
* {{Z|se}}: {{W-|se|čáhppes}}
* {{Z|sa}}: {{W+|sa|कृष्ण}}, {{W+|sa|काला}}
* Sardinian:
*: {{Z|sc}}: {{W-|sc|nieddu|n}}
*: {{Z|sc}}: {{W-|sc|niéddhu|n}}
*: {{Z|sc}}: {{W-|sc|nigheddu|n}}
* {{Z|sas}}: {{W-|sas|bidəŋ}}
* {{Z|ceb}}: {{W-|ceb|itom}}
* {{Z|scn}}: {{W+|scn|nìuru}}
* {{Z|sd}}: {{W+|sd|ڪارو}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|цр̑н}}
*: Latînî: {{W+|sh|cȓn}}
* {{Z|syl}}: {{W-|syl|ꠇꠣꠟꠣ}}
* {{Z|cu}}: {{W-|cu|чрьнъ}}
* {{Z|sk}}: {{W-|sk|čierny}}
* {{Z|sl}}: {{W+|sl|črn}}
* {{Z|zlw-slv}}: {{W-|zlw-slv|čǻrnï}}
* {{Z|so}}: {{W+|so|madow}}
* Sorbî:
*: {{Z|dsb}}: {{W-|dsb|carny}}
*: {{Z|hsb}}: {{W+|hsb|čorny}}
* {{Z|es}}: {{W+|es|negro}}
* {{Z|su}}: {{W-|su|hideung}}
* {{Z|sva}}: {{W-|sva|მეშხე}}
* {{Z|sw}}: {{W-|sw|eusi}}
* {{Z|ss}}: {{W-|ss|mnyáma}}
* {{Z|sv}}: {{W+|sv|svart}}
* {{Z|shy}}: {{W-|shy|aberkan}}
* {{Z|xsr}}: {{W-|xsr|ནག་པུ|tr=nakpu}}
* {{Z|zdj}}: {{W-|zdj|-[[ɗu]]}}
* {{Z|sn}}: {{W-|sn|dema}}
* {{Z|cjs}}: {{W-|cjs|қара|tr=qara}}
* {{Z|tab}}: {{W-|tab|кӏару}}
* {{Z|tg}}: {{W+|tg|сиёҳ}}
* {{Z|tl}}: {{W+|tl|itim}}
* {{Z|ty}}: {{W-|ty|ʻereʻere}}
* {{Z|ta}}: {{W+|ta|கருப்பு}}
* {{Z|roa-tar}}: {{W-|roa-tar|gnure}}
* {{Z|rif}}: {{W-|rif|aberkan|n}}
* {{Z|tsg}}: {{W-|tsg|maitum}}
* {{Z|th}}: {{W+|th|ดำ}}
* {{Z|te}}: {{W+|te|నల్ల}}, {{W+|te|నల్లని}}
* {{Z|tt}}: {{W+|tt|кара}}
* {{Z|tr}}: {{W+|tr|kara}}, {{W+|tr|siyah}}
* {{Z|tk}}: {{W-|tk|gara}}
* {{Z|bo}}: {{W-|bo|ནག་པོ}}, {{W-|bo|ནག་ཅན}}, {{W-|bo|རོག་རོག}}
* {{Z|to}}: {{W-|to|ʻuliʻuli}}
* {{Z|txb}}: {{W-|txb|erkent}}
* {{Z|udm}}: {{W-|udm|сьӧд}}
* {{Z|ur}}: {{W-|ur|کالا|n|tr=kālā}}, {{W-|ur|سیاہ}}
* {{Z|uk}}: {{W+|uk|чо́рний}}
* {{Z|vi}}: {{W+|vi|đen}}, {{W+|vi|đen thui}}
* {{Z|vo}}: {{W+|vo|blägik}}
* {{Z|wa}}: {{W+|wa|noer}}
* {{Z|cy}}: {{W+|cy|du}}
* {{Z|win}}: {{W-|win|seep}}
* {{Z|wo}}: {{W-|wo|kawe-yolet}}
* {{Z|kjh}}: {{W-|kjh|хара}}
* {{Z|km}}: {{W+|km|ខ្មៅ|tr=kmav}}
* {{Z|yai}}: {{W-|yai|шов}}
* {{Z|sah}}: {{W-|sah|хара}}
* {{Z|yi}}: {{W-|yi|שוואַרץ}}
* {{Z|el}}: {{W+|el|μαύρος|n}}
*: Kevn: {{W-|grc|μέλας}}
* {{Z|zea}}: {{W-|zea|zwart}}
* {{Z|za}}: {{W-|za|ndaem}}, {{W-|za|fonx}}
* {{Z|zu}}: {{W+|zu|-[[mnyama]]}}{{werger-bin}}
=== Navdêr ===
{{ku-tewîn-nav|reş|nêr}}
{{navdêr|ku|z=n}}
# [[reng|Reng]]ê reş.
#* {{jêder|ku|jêgirtin=Wekû muddeyê hiznê (dema xemgîniyê) temam bûyî axayêd wan û yaxo xizmekî wan ji boy her yekî ehlê meyyitî, anegore halê xwe tiştekî tîne û '''reşêd''' wan heldigire, ji şînê biderdikevin. Lakin eger ew meyyit begzade û yaxo axa û mirovekî kifş bûya elbette paşî panzdeh rojan hakimê wî welatî xelatek hazir dikirîn û dişande pê warisê meyyitî (xwediyê kesê ku miriye) û tînane hizûra xwe û digotêne: Emrê xwedê ye, bilanî tu xweş bî, mirin rêya me hemûyan e. Ew xelat li wî warisî dikirîn û ji '''reşê''' biderdanîn (derdixistin).|{{jêgirtin/Mele Mehmûdê Bayezîdî/Adat û Rusûmatnameê Ekradiye|r=53}}}}
==== Werger ====
{{werger-ser}}
* {{Z|fr}}: {{W+|fr|noir|n}}
{{werger-bin}}
== {{ziman|ckb}} ==
=== Rengdêr ===
{{rengdêr|ckb|sc=Latn}}
# {{ckb-Arab|ڕەش}}
pb7jisvdu5o8wtpwsch5ithkn6akx89
6241661
6241660
2026-07-11T20:24:31Z
Wikihez
7344
6241661
wikitext
text/x-wiki
{{bnr-h|res}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-reş.wav|Deng|Wan}}
* {{ku-kîte}}
=== Rengdêr ===
{{ku-tewîn-rd|reş}}
[[Wêne:Solid black.svg|thumb|150px|Rengê reş.]]
{{rengdêr|ku}}
# {{f|ku|reng}} [[reng|Reng]]ê ji hemiyan [[tarî]]tir, [[wek]] rengê [[rejî|rejiyê]].
#: {{panela rengê|000000}}
#* {{jêder|ku|jêgirtin=-Tu jî mîna Fêdkayê min esmer î, çevreş, porê te '''reş'''.|{{Jêgirtin/Frîda Hecî Cewarî/Bîranînên Min}}}}
#* {{jêder|ku|jêgirtin=Digel ku emrê wî hê sî û pênc bû jî tayekî '''reş''' di porê wî de nemabû.|{{Jêgirtin/Firat Cewerî/Kevoka Spî/1996}}}}
#* {{jêder|ku|jêgirtin=Û ew libasêd '''reş''' heta şeş mehan û yaxo salekê li ser ehlê (xizmê) meyyitî dimînin. Ew ehlê meyyitî heta ji şînê bidernekevin naçine dawet û kêfxweşiyan.|{{jêgirtin/Mele Mehmûdê Bayezîdî/Adat û Rusûmatnameê Ekradiye|r=53}}}}
# Ji [[ronahî|ronahiyê]] [[bêpar]].
#: {{hevmane|ku|tarî}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Saqî ko dêm mehweş bitin<br />Kagul ji şêva '''reş''' bitin<br />Qerqef bila ateş bitin}}
#* {{jêder|ku|jêgirtin=(...) mîna tîrekê navdilê Qaçax hingavtin, ling lê lerizîn, ber çavên wî '''reş''' bû (...)|{{Jêgirtin/Sîma Semend/Xezal/1996}}}}
# [[temirandî]]
#: {{nm|ku|Ka wê çirayê '''reş''' bike.}}
# [[mirov|Mirov]]ên [[çerm]]reş yên mîna [[Afrîkî|afrîkiyan]].
#: {{hevmane|ku|çermreş}}
#* {{jêder|ku|jêgirtin=Zelamekê req û hişk û '''reş''' hate bi nik wan ve.|{{Jêgirtin/Xelîl Duhokî/Antolojiya Çîroka Nû ya Kurmancên Başûr}}}}
# [[bêyom]], [[pirr]] [[xirab]], [[nebaş]]
#* {{jêder|ku|jêgirtin=Bextê me '''reş''' e, kezeb birîn e.|{{Jêgirtin/Mehmed Uzun/Siya Evînê/1989}}}}
==== Bi alfabeyên din ====
* {{ku-ar|ڕەش}}
* {{ku-kr|рәш}}
==== Herwiha ====
* {{hw|ku|riş||Reşwî}}
==== Hevmane ====
* {{g|ku|siyah}} {{i|tenê [[edebî]]}}
* {{g|ku|qere-}} {{i|tenê wek [[pêşgir]]}}
==== Jê ====
{{kol3|ku|cure=Jê
|reş bûn<q:lêker>
|reş kirin<q:lêker>
|reşbûn<q:navdêr>
|reşkirin<q:navdêr>
|reşbûyî<q:rengdêr>
|reşkirî<q:rengdêr>
|reşokî
|reşole
|reşnivîs
|reşmeh
|reşname
|reşpatî
|ripîreş
}}
==== Etîmolojî ====
Taliyê ji {{ji|ira-pro|ku|*ra(n)ǰ-|w=reng kirin, boyax kirin}}.
Hevreha {{hv|ckb|ڕەش}}, {{hv|kho|rraşa|w=ya ku bi rengê tarî}}, {{hv|tly|رش|tr=rəş|w=qehweyiya zelal}}, {{hv|sog|tr=rɣš-|ts=raxš|w={{w|Rexş}}, hespê [[Ristem]]}}, {{hv|fa|رخش|tr=rexş|w=sor}}, {{hv|mzn|رش|tr=raš|w=sor}}. Guherîna maneya rengan di zimanên hindûewropî de diyardeyeke berbelav e.
;{{biçûk|Çavkanî:
* {{Cheung|r=314}}
}}
==== Binêre herwiha ====
{{tablo:reng/ku}}
==== Bide ber ====
* {{g|ku|reştarî}}
* {{g|ku|reşûşîn kirin}}
* {{g|ku|reşûşîn}}
* {{g|ku|reşpoş}}
==== Bi zaravayên din ====
* {{Z|ckb}}: {{W-|ckb|ڕەش|tr=reş}}
* {{Z|sdh}}: {{W-|sdh|siya|sc=Latn}}, {{W-|sdh|siyaw|sc=Latn}}
* {{Z|hac}}: {{W-|hac|siyaw|sc=Latn}}
* {{Z|zza}}: {{W-|zza|sîya}}
==== Werger ====
{{werger-ser}}
* {{Z|ab}}: {{W-|ab|аиқәаҵәа}}
* {{Z|ace}}: {{W-|ace|itam}}
* {{Z|adt}}: {{W-|adt|waurrunha}}
* {{Z|af}}: {{W+|af|swart}}
* {{Z|akl}}: {{W-|akl|maitum}}
* {{Z|sq}}: {{W+|sq|zi}}
* {{Z|de}}: {{W+|de|schwarz}}
* {{Z|alt}}: {{W-|alt|кара}}
* {{Z|am}}: {{W-|am|ጥቁር}}
* {{Z|ani}}: {{W-|ani|бечӏедир}}
* {{Z|rme}}: {{W-|rme|kalo}}
* Apaçî:
*: {{Z|apw}}: {{W-|apw|diłhił}}
* {{Z|an}}: {{W-|an|negro}}
* {{Z|rup}}: {{W-|rup|negru}}, {{W+|rup|laiu}}
* {{Z|aer}}: {{W-|aer|artepe}}
* {{Z|as}}: {{W-|as|ক’লা}}, {{W-|as|কুলা}}
* {{Z|ast}}: {{W+|ast|ñegru}}, {{W+|ast|negru}}, {{W+|ast|prietu}}
* {{Z|cni}}: {{W-|cni|cheenkari}}, {{W-|cni|kisaari}}
* {{Z|atj}}: {{W-|atj|makatewaw}}
* {{Z|aot}}: {{W-|aot|pinak}}
* {{Z|av}}: {{W-|av|чӏегӏера}}, {{W-|av|чӏегӏераб}}
* {{Z|ay}}: {{W-|ay|ch’iyara}}
* {{Z|az}}: {{W+|az|qara}}
* {{Z|ban}}: {{W-|ban|badeng}}
* {{Z|bjn}}: {{W-|bjn|hirang}}
* {{Z|eu}}: {{W-|eu|beltz}}
* {{Z|ba}}: {{W-|ba|ҡара}}
* {{Z|bbl}}: {{W-|bbl|ჺარჭინ}}
* {{Z|be}}: {{W+|be|чо́рны}}
* {{Z|bn}}: {{W+|bn|কালো}}, {{W+|bn|কাল}}
* {{Z|br}}: {{W+|br|du}}
* {{Z|bug}}: {{W-|bug|ma-lotoŋ}}
* {{Z|mbb}}: {{W-|mbb|me'item}}
* {{Z|bg}}: {{W+|bg|че́рен}}
* {{Z|my}}: {{W+|my|နက်}}, {{W+|my|မည်း}}
* {{Z|bua}}: {{W-|bua|хара}}
* {{Z|kac}}: {{W-|kac|chyang}}
* {{Z|dz}}: {{W-|dz|གནགཔོ}}
* {{Z|ccc}}: {{W-|ccc|kosewa}}
* {{Z|ce}}: {{W-|ce|ӏаьржа}}
* {{Z|cs}}: {{W+|cs|černý}}
* {{Z|chr}}: {{W-|chr|ᎬᎿᎨ}}
* {{Z|cic}}: {{W-|cic|losa'}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|黑|tr=hak1}}, {{W-|yue|黑色|tr=haak1 sik1, hak1 sik1}}
*: {{Z|dng}}: {{W-|dng|хи}}
*: {{Z|cmn}}: {{W+|cmn|黑|tr=hēi}}, {{W+|cmn|黑色|tr=hēisè}}, {{W+|cmn|烏色|tr=wūsè}}
*: {{Z|cdo}}: {{W-|cdo|烏|tr=ŭ}}
*: {{Z|nan}}: {{W-|nan|黑|tr=hek}}, {{W-|nan|黑色|tr=hek-sek}}, {{W+|nan|烏色|tr=o͘-siak / o͘-sek}}
*: {{Z|wuu}}: {{W-|wuu|黑}}
* {{Z|cv}}: {{W-|cv|хура}}
* {{Z|chk}}: {{W-|chk|chon}}
* {{Z|dlm}}: {{W-|dlm|fosc}}
* {{Z|da}}: {{W+|da|sort}}
* {{Z|dgr}}: {{W-|dgr|dezǫ}}
* {{Z|dlg}}: {{W-|dlg|кара}}
* {{Z|ovd}}: {{W-|ovd|swart}}
* {{Z|id}}: {{W+|id|hitam}}
* {{Z|ar}}: {{W+|ar|أَسْوَد|n}}, {{W-|ar|سَوْدَاء|m}}, {{W-|ar|سُود|p}}
*: {{Z|arz}}: {{W-|arz|اسود|tr=eswid}}
*: {{Z|acw}}: {{W-|acw|أسود|tr=ʾaswad}}
*: {{Z|ary}}: {{W-|ary|كحل|tr=kḥal}}, {{W-|ary|سود|tr=swad}}
* {{Z|hy}}: {{W-|hy|սև}}
* {{Z|myv}}: {{W-|myv|раужо}}
* {{Z|eo}}: {{W+|eo|nigra}}
* {{Z|et}}: {{W+|et|must}}
* {{Z|ett}}: {{W-|ett|𐌑𐌖𐌓𐌉}}
* {{Z|eve}}: {{W-|eve|хакарин}}
* {{Z|evn}}: {{W-|evn|конңорин}}
* {{Z|ee}}: {{W-|ee|yibɔ}}
* {{Z|ext}}: {{W-|ext|negru}}
* {{Z|fa}}: {{W+|fa|سیاه|tr=siyâh}}
* {{Z|fo}}: {{W+|fo|svartur}}
* {{Z|fj}}: {{W+|fj|loaloa}}
* {{Z|fi}}: {{W+|fi|musta}}
* {{Z|fr}}: {{W+|fr|noir}}
* {{Z|fur}}: {{W-|fur|neri}}
* {{Z|frr}}:
*: Föhr: {{W-|frr|suart}}
*: Hallig: {{W-|frr|süürt}}
*: {{Z|frr}}: {{W-|frr|suurt}}
* {{Z|fy}}: {{W+|fy|swart}}
* {{Z|gd}}: {{W+|gd|dubh}}
* {{Z|gl}}: {{W+|gl|negro}}
* {{Z|gdo}}: {{W-|gdo|бечӏер}}
* {{Z|gon}}: {{W-|gon|నల్లా|tr=nallā}}
* {{Z|gor}}: {{W-|gor|yitomo}}
* {{Z|got}}: {{W-|got|𐍃𐍅𐌰𐍂𐍄𐍃}}
* {{Z|gu}}: {{W+|gu|કાળું}}
* {{Z|ka}}: {{W+|ka|შავი}}
* {{Z|ht}}: {{W-|ht|nwa}}
* {{Z|hur}}: {{W-|hur|ts'q'éyx̱}}
*: {{Z|hur}}: {{W-|hur|tsq'ix}}
* {{Z|haw}}: {{W-|haw|ʻeleʻele}}
* {{Z|mba}}: {{W-|mba|maitum}}
* {{Z|hi}}: {{W+|hi|काला}}, {{W+|hi|कारौ}}
* {{Z|hil}}: {{W-|hil|maitum}}
* {{Z|mww}}: {{W-|mww|dub}}
* {{Z|nl}}: {{W+|nl|zwart}}
* {{Z|hop}}: {{W-|hop|qömvi}}
* {{Z|ibg}}: {{W-|ibg|ngisit}}
* {{Z|he}}: {{W+|he|שחור|tr=shakhór|cuda=שחור \ שָׁחֹר}}, {{W-|he|שחורה|m|tr=sh'khorá|cuda=שחורה \ שְׁחֹרָה}}
* {{Z|io}}: {{W+|io|nigra}}
* {{Z|ig}}: {{W-|ig|nwa}}
* {{Z|ilo}}: {{W-|ilo|nangisit}}
* {{Z|ang}}: {{W-|ang|blæc}}, {{W-|ang|sweart}}
* {{Z|en}}: {{W+|en|black}}
* {{Z|inh}}: {{W-|inh|ӏаьржа}}
* {{Z|ia}}: {{W+|ia|nigre}}
* {{Z|ill}}: {{W-|ill|maitem}}
* {{Z|ga}}: {{W+|ga|dubh}}
* {{Z|isd}}: {{W-|isd|ngisit}}
* {{Z|ist}}: {{W-|ist|nìgaro}}, {{W-|ist|nìgro}}
* {{Z|it}}: {{W+|it|nero}}
* {{Z|ium}}: {{W-|ium|jieqv}}
* {{Z|is}}: {{W+|is|svartur}}
* {{Z|ja}}: {{W+|ja|黒い|tr=くろい, kuroi}}, {{W-|ja|[[黒色]]の|tr=こくしょくの, kokushoku no}}
* {{Z|jv}}: {{W+|jv|ireng}}, {{W-|jv|ireŋ}}, {{W-|jv|cemeŋ}}, {{W-|jv|hirěng}}
* {{Z|kl}}: {{W+|kl|qernertoq}}
* {{Z|xal}}: {{W-|xal|хар}}
* {{Z|kn}}: {{W+|kn|ಕಪ್ಪು}}
* {{Z|pam}}: {{W-|pam|matuling}}
* {{Z|krc}}: {{W-|krc|къара|tr=qara}}
* {{Z|csb}}: {{W-|csb|czôrny}}
* {{Z|ca}}: {{W+|ca|negre}}
* {{Z|zku}}: {{W-|zku|pulyuna}}
* {{Z|qu}}: {{W-|qu|yana}}
* {{Z|kjj}}: {{W-|kjj|мичӏаь}}
* {{Z|ky}}: {{W+|ky|кара}}, {{W-|ky|күңүрт кара}}, {{W+|ky|караңгы}}, {{W+|ky|каралоо}}, {{W+|ky|ушактоо}}, {{W+|ky|жамандоо}}, {{W+|ky|жаманатты кылуу}}, {{W+|ky|жала жабуу}}, {{W+|ky|көө}}
* {{Z|kg}}: {{W-|kg|ndombe}}
* {{Z|ki}}: {{W-|ki|-irũ}}
* {{Z|si}}: {{W+|si|කළු}}
* {{Z|koi}}: {{W-|koi|сьӧд}}
* {{Z|ko}}: {{W+|ko|검다}}, {{W+|ko|검은}}, {{W+|ko|까맣다}}, {{W-|ko|까만}}
* {{Z|kw}}: {{W-|kw|du}}
* {{Z|co}}: {{W+|co|neru}}
* {{Z|mfe}}: {{W-|mfe|nwar}}
* {{Z|kum}}: {{W-|kum|къара|tr=qara}}
* {{Z|qui}}: {{W-|qui|shĺpa}}
* {{Z|lbj}}: {{W-|lbj|ནག་པོ}}
* {{Z|lld}}: {{W-|lld|fosch|n}}
* {{Z|lad}}: {{W-|lad|preto}}
* {{Z|lkt}}: {{W-|lkt|sápa}}
* {{Z|ltg}}: {{W-|ltg|malns}}
* {{Z|la}}: {{W+|la|ater}}, {{W+|la|niger}}
* {{Z|lv}}: {{W+|lv|melns}}
* {{Z|lo}}: {{W-|lo|ດຳ}}
* {{Z|lez}}: {{W-|lez|чӏулав}}
* {{Z|mhx}}: {{W-|mhx|no, |tr=nòʔ}}
* {{Z|ln}}: {{W-|ln|moíndo}}
* {{Z|lij}}: {{W-|lij|néigro}}
* {{Z|li}}: {{W+|li|zwart}}
* {{Z|lt}}: {{W-|lt|júodas}}
* {{Z|lmo}}: {{W-|lmo|négher}}, {{W-|lmo|negro}}
* {{Z|khb}}: {{W-|khb|ᦡᧄ}}
* {{Z|mhn}}: {{W-|mhn|schbòrz}}
* {{Z|mad}}: {{W-|mad|celleng}}
* {{Z|mak}}: {{W-|mak|le'leng}}
* {{Z|mk}}: {{W-|mk|црн}}
* {{Z|mg}}: {{W+|mg|mainty}}
* {{Z|ml}}: {{W+|ml|കറുപ്പ്}}
* {{Z|ms}}: {{W+|ms|hitam}}, {{W+|ms|aswad}}, {{W-|ms|lotong}}, {{W-|ms|lutung}}, {{W-|ms|lutong}}
*: {{Z|ms}}: {{W-|ms|هيتم}}, {{W-|ms|اسود}}, {{W-|ms|لوتوڠ}}
* {{Z|mt}}: {{W+|mt|iswed|n}}, {{W-|mt|sewda|m}}, {{W-|mt|suwed|p}}
* {{Z|mnc}}: {{W-|mnc|ᠰᠠᡥᠠᠯᡳᠶᠠᠨ}}, {{W-|mnc|ᡴᠠᡵᠠ|tr=kara}}
* {{Z|gv}}: {{W-|gv|doo}}
* {{Z|msk}}: {{W-|msk|maitum}}
* {{Z|mi}}: {{W+|mi|mangu}}
* {{Z|mrw}}: {{W-|mrw|maitem}}, {{W-|mrw|delem}}
* {{Z|mr}}: {{W+|mr|काळा|n}}
* {{Z|mrc}}: {{W-|mrc|nilyig}}
* {{Z|mop}}: {{W-|mop|bʼox}}
* {{Z|hu}}: {{W+|hu|fekete}}
* {{Z|egy}}: {{W-egy|km|h=km-m-D3}}
* {{Z|lus}}: {{W-|lus|dum}}
* {{Z|min}}: {{W-|min|itam}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|хар}}
*: Mongolî: {{W-|mn|ᠬᠠᠷᠠ}}
* {{Z|nfr}}: {{W-|nfr|wɔɔ}}
* Nahuatl:
*: {{Z|nhn}}: {{W-|nhn|tliltic}}
*: Klasîk: {{W-|nci|tliltic}}, {{W-|nci|capotztic}}
* {{Z|naq}}: {{W-|naq|ǂnū}}
* {{Z|nmb}}: {{W-|nmb|im'ət}}
* {{Z|gld}}: {{W-|gld|сахарин}}
* {{Z|nap}}: {{W-|nap|niro}}
* {{Z|nv}}: {{W-|nv|łizhin}}
* {{Z|na}}: {{W+|na|etangang}}, {{W-|na|etañañ}}, {{W-|na|etaŋaŋ}}
* {{Z|nxq}}: {{W-|nxq|naq}}
* {{Z|nds}}:
*: {{Z|nds-de}}: {{W-|nds-de|swart}}
* {{Z|ne}}: {{W+|ne|कालो}}
* {{Z|nay}}: {{W-|nay|kro:tin}}
* {{Z|nia}}: {{W-|nia|a-itö}}
* {{Z|nog}}: {{W-|nog|кара}}
* {{Z|nuk}}: {{W-|nuk|tupkuk}}
* {{Z|nrf}}: {{W-|nrf|nièr|n}}, {{W-|nrf|né|n}}, {{W-|nrf|néthe|m}}, {{W-|nrf|naithe|m}}
* {{Z|non}}: {{W-|non|svartr}}, {{W-|non|blakkr}}
* {{Z|no}}: {{W+|no|svart}}, {{W+|no|sort}}
* {{Z|nwy}}: {{W-|nwy|gahuntee}}
* {{Z|ood}}: {{W-|ood|chuk}}
* {{Z|oj}}: {{W-|oj|makade-}}, {{W-|oj|makadewaa}}, {{W-|oj|makadewizi}}
* {{Z|oc}}: {{W+|oc|negre}}
* {{Z|or}}: {{W+|or|କଲା}}
* {{Z|om}}: {{W+|om|gurraacha}}
* {{Z|os}}: {{W-|os|сау}}
* {{Z|ug}}: {{W+|ug|قارا}}
* {{Z|uz}}: {{W+|uz|qora}}, {{W+|uz|siyoh}}
* {{Z|pag}}: {{W-|pag|deket}}
* {{Z|ps}}: {{W+|ps|تور}}
* {{Z|pms}}: {{W-|pms|neir}}
* {{Z|pjt}}: {{W-|pjt|maṟu}}
* {{Z|pl}}: {{W+|pl|czarny}}
* {{Z|pt}}: {{W+|pt|preto}}, {{W+|pt|atro}}, {{W+|pt|negro}}
* {{Z|pa}}: {{W+|pa|ਕਾਲਾ}}
* {{Z|kk}}: {{W+|kk|қара}}
* {{Z|cop}}: {{W-|cop|ⲭⲁⲙⲉ}}
* {{Z|rap}}: {{W-|rap|kere kere}}, {{W-|rap|uri uri}}
* {{Z|rhg}}: {{W-|rhg|hala}}
* {{Z|rgn}}: {{W-|rgn|négar}}
* {{Z|rm}}: {{W-|rm|nair}}
* {{Z|rom}}: {{W-|rom|kalo}}
*: {{Z|rmn}}: {{W-|rmn|kalo}}
*: {{Z|rml}}: {{W-|rml|kalo}}
*: {{Z|rmc}}: {{W-|rmc|kalo}}
*: {{Z|rmo}}: {{W-|rmo|kalo}}
*: {{Z|rmy}}: {{W-|rmy|kalo}}
* {{Z|ro}}: {{W+|ro|negru}}
* {{Z|ru}}: {{W+|ru|чёрный}}, {{W+|ru|вороно́й}}
* {{Z|str}}: {{W-|str|NEKIX}}
* {{Z|se}}: {{W-|se|čáhppes}}
* {{Z|sa}}: {{W+|sa|कृष्ण}}, {{W+|sa|काला}}
* Sardinian:
*: {{Z|sc}}: {{W-|sc|nieddu|n}}
*: {{Z|sc}}: {{W-|sc|niéddhu|n}}
*: {{Z|sc}}: {{W-|sc|nigheddu|n}}
* {{Z|sas}}: {{W-|sas|bidəŋ}}
* {{Z|ceb}}: {{W-|ceb|itom}}
* {{Z|scn}}: {{W+|scn|nìuru}}
* {{Z|sd}}: {{W+|sd|ڪارو}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|цр̑н}}
*: Latînî: {{W+|sh|cȓn}}
* {{Z|syl}}: {{W-|syl|ꠇꠣꠟꠣ}}
* {{Z|cu}}: {{W-|cu|чрьнъ}}
* {{Z|sk}}: {{W-|sk|čierny}}
* {{Z|sl}}: {{W+|sl|črn}}
* {{Z|zlw-slv}}: {{W-|zlw-slv|čǻrnï}}
* {{Z|so}}: {{W+|so|madow}}
* Sorbî:
*: {{Z|dsb}}: {{W-|dsb|carny}}
*: {{Z|hsb}}: {{W+|hsb|čorny}}
* {{Z|es}}: {{W+|es|negro}}
* {{Z|su}}: {{W-|su|hideung}}
* {{Z|sva}}: {{W-|sva|მეშხე}}
* {{Z|sw}}: {{W-|sw|eusi}}
* {{Z|ss}}: {{W-|ss|mnyáma}}
* {{Z|sv}}: {{W+|sv|svart}}
* {{Z|shy}}: {{W-|shy|aberkan}}
* {{Z|xsr}}: {{W-|xsr|ནག་པུ|tr=nakpu}}
* {{Z|zdj}}: {{W-|zdj|-[[ɗu]]}}
* {{Z|sn}}: {{W-|sn|dema}}
* {{Z|cjs}}: {{W-|cjs|қара|tr=qara}}
* {{Z|tab}}: {{W-|tab|кӏару}}
* {{Z|tg}}: {{W+|tg|сиёҳ}}
* {{Z|tl}}: {{W+|tl|itim}}
* {{Z|ty}}: {{W-|ty|ʻereʻere}}
* {{Z|ta}}: {{W+|ta|கருப்பு}}
* {{Z|roa-tar}}: {{W-|roa-tar|gnure}}
* {{Z|rif}}: {{W-|rif|aberkan|n}}
* {{Z|tsg}}: {{W-|tsg|maitum}}
* {{Z|th}}: {{W+|th|ดำ}}
* {{Z|te}}: {{W+|te|నల్ల}}, {{W+|te|నల్లని}}
* {{Z|tt}}: {{W+|tt|кара}}
* {{Z|tr}}: {{W+|tr|kara}}, {{W+|tr|siyah}}
* {{Z|tk}}: {{W-|tk|gara}}
* {{Z|bo}}: {{W-|bo|ནག་པོ}}, {{W-|bo|ནག་ཅན}}, {{W-|bo|རོག་རོག}}
* {{Z|to}}: {{W-|to|ʻuliʻuli}}
* {{Z|txb}}: {{W-|txb|erkent}}
* {{Z|udm}}: {{W-|udm|сьӧд}}
* {{Z|ur}}: {{W-|ur|کالا|n|tr=kālā}}, {{W-|ur|سیاہ}}
* {{Z|uk}}: {{W+|uk|чо́рний}}
* {{Z|vi}}: {{W+|vi|đen}}, {{W+|vi|đen thui}}
* {{Z|vo}}: {{W+|vo|blägik}}
* {{Z|wa}}: {{W+|wa|noer}}
* {{Z|cy}}: {{W+|cy|du}}
* {{Z|win}}: {{W-|win|seep}}
* {{Z|wo}}: {{W-|wo|kawe-yolet}}
* {{Z|kjh}}: {{W-|kjh|хара}}
* {{Z|km}}: {{W+|km|ខ្មៅ|tr=kmav}}
* {{Z|yai}}: {{W-|yai|шов}}
* {{Z|sah}}: {{W-|sah|хара}}
* {{Z|yi}}: {{W-|yi|שוואַרץ}}
* {{Z|el}}: {{W+|el|μαύρος|n}}
*: Kevn: {{W-|grc|μέλας}}
* {{Z|zea}}: {{W-|zea|zwart}}
* {{Z|za}}: {{W-|za|ndaem}}, {{W-|za|fonx}}
* {{Z|zu}}: {{W+|zu|-[[mnyama]]}}{{werger-bin}}
=== Navdêr ===
{{ku-tewîn-nav|reş|nêr}}
{{navdêr|ku|z=n}}
# [[reng|Reng]]ê reş.
#* {{jêder|ku|jêgirtin=Wekû muddeyê hiznê (dema xemgîniyê) temam bûyî axayêd wan û yaxo xizmekî wan ji boy her yekî ehlê meyyitî, anegore halê xwe tiştekî tîne û '''reşêd''' wan heldigire, ji şînê biderdikevin. Lakin eger ew meyyit begzade û yaxo axa û mirovekî kifş bûya elbette paşî panzdeh rojan hakimê wî welatî xelatek hazir dikirîn û dişande pê warisê meyyitî (xwediyê kesê ku miriye) û tînane hizûra xwe û digotêne: Emrê xwedê ye, bilanî tu xweş bî, mirin rêya me hemûyan e. Ew xelat li wî warisî dikirîn û ji '''reşê''' biderdanîn (derdixistin).|{{jêgirtin/Mele Mehmûdê Bayezîdî/Adat û Rusûmatnameê Ekradiye|r=53}}}}
==== Werger ====
{{werger-ser}}
* {{Z|fr}}: {{W+|fr|noir|n}}
{{werger-bin}}
== {{ziman|ckb}} ==
=== Rengdêr ===
{{rengdêr|ckb|sc=Latn}}
# {{ckb-Arab|ڕەش}}
d336mtiiix970cfh909eviim1v8kdwu
pel
0
3393
6241662
6103593
2026-07-11T20:30:05Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241662
wikitext
text/x-wiki
{{binêre herwiha/pel}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA|pʰɛl}}
* {{ku-kîte}}
=== Navdêr 1 ===
{{ku-tewîn-nav|pel|nêr}}
[[Wêne:Leaf 1 web.jpg|thumb|pel (1)]]
{{navdêr|ku|z=n}}, {{p-ya req}}
# {{maneid|ku|riwek}} [[parçe|Parçe]]yên [[çeq]]ên [[dar]]an ve [[şên]] dibin. ([[pêşî]] ji [[bişkoj]]an [[pişkivîn|dipişkivin]], [[paşî]] [[kesk]] dibin û [[talî|taliyê]] [[beyîn|dibeyin]] anku [[zer]] dibin û [[werîn|diwerin]] anku [[weşîn|diweşin]])
#: {{hevmane|ku|belçim|belçîm|bilçik|belçûm|pelçim|pelçîm|pelçûm}}
# [[per]], [[kaxez]], [[weraqe]], [[belgename]]
==== Bi alfabeyên din ====
* {{ku-ar|پەل}}
==== Ji wêjeya klasîk ====
* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Ah-i bêgavê ji dil tên me ji pêta di ceger</br>Bes tu bêfeyde nesîhet ke me dil bûye '''pelek'''}}
==== Herwiha ====
{{kol3|ku|cure=Herwiha|sernav = [https://twitter.com/wikiferheng/status/1710338730089689440 Çavkanî]
| {{hw|ku|pelg||Sirûc|Bîraçik|Xelfetî}}
| {{hw|ku|pel||Mêrdîn|Sêwreg|Amed|Pasûr|Çewlîg|Bazîd}}
| {{hw|ku|pelçim||Botan}}
| {{hw|ku|belg||Dîgor|Agirî|Wan}}
| {{hw|ku|belçim||Dêrsim|Serhed}}
| {{hw|ku|pelç||Hewag}}
| {{hw|ku|per||Semsûr}}
}}
==== Bide ber ====
{{stûn|
* {{g|ku|pell}}
* {{g|ku|pal}}
* {{g|ku|pêl}}
* {{g|ku|pil}}
* {{g|ku|pîl}}
* {{g|ku|pol}}
* {{g|ku|pul}}
* {{g|ku|pûl}}
* {{g|ku|bel}}
}}
==== Jê ====
{{kol3|ku|cure=Jê
|pel girtin<q:lêker>
|pelgirtin<q:navdêr>
|pelçûn<q:navdêr>
}}
==== Etîmolojî ====
Hevreha şêxbizinî ''[[welg]]'', zazakî ''[[velg]]''
* {{ji|ine-pro|ku|-}}: *'''welə'''- ("hirî, pûrt") > *'''wolko'''- ("mû, hirî, pûrt; giya; daristan")
:*{{ji|ira-pro||-}}: *'''warka'''- ("belg, pel")
::{{ae}}: '''verke'''- ("belg, pel")
::{{xpr}}: '''wrgr''' ("belg, pel")
::{{pal}}: '''werg ''' ("belg, pel")
::{{sog}}: '''wrkr ''' ("belg, pel")
::{{fa}}: '''berg''' ("belg, pel")
::{{mzn}}: '''verek''' ("belg, pel")
::{{ku}}: '''belg > pelg > pel'''
::{{zza}}: '''[[velg]]''' ("belg, pel")
:{{sa}}: '''velke'''- ("[[per]], [[bask]]") ...
:{{la}}: '''vellus'''- ("hirî, pûrt")
:{{de}}: '''Wolle'''- ("hirî, pûrt")
:{{en}}: '''wool'''- ("hirî, pûrt")
;{{biçûk|Çavkanî:
* {{Horn|r=47}}
* {{Lubotsky|r=98}}
* {{Pokorny|r=1139}}
}}
==== Bi zaravayên din ====
* soranî/erdelanî: gella, pelk
* zazakî/kirmanckî: pel, pelçim, pure, velg,
* kelhûrî/feylî/şêxbizinî: welg, welneg, werg, belg, berg, pelg
* hewramî/şebekî: welg
==== Werger ====
{{werger-ser|riwek|id=riwek}}
* {{Z|ab}}: {{W-|ab|абӷьы}}
* {{Z|ace}}: {{W-|ace|ôn}}
* {{Z|ady}}: {{W-|ady|тхьэпкӏэ}}
* {{Z|aa}}: {{W-|aa|dalaa}}
* {{Z|af}}: {{W+|af|blaar}}
* {{Z|akl}}: {{W-|akl|dahon}}
* {{Z|sq}}: {{W+|sq|gjethe|m-p}}
* {{Z|pdc}}: {{W-|pdc|Blatt|nt}}
* {{Z|de}}: {{W+|de|Blatt|nt}}, {{W+|de|Laubblatt|nt}}
*: {{Z|gsw}}: {{W-|gsw|Blatt|nt}}
*: {{Z|gmw-cfr}}: {{W-|gmw-cfr|Blatt|nt}}
* {{Z|ryn}}: {{W-|ryn|葉|tr=はー, hā}}
* {{Z|ams}}: {{W-|ams|葉|tr=はー, hā}}
* {{Z|am}}: {{W-|am|ቅጠል}}
* {{Z|an}}: {{W+|an|fuella|m}}
* {{Z|arc}}:
*: {{Z|syc}}: {{W-|syc|ܛܪܦܐ|n|tr=ṭarpā}}
* {{Z|agj}}: {{W-|agj|ቅጠል|tr=qəțäl}}
* {{Z|rup}}: {{W-|rup|frãndzã|m}}, {{W-|rup|frundzã|m}}
* {{Z|as}}: {{W-|as|পাত|nt}}
* {{Z|bno}}: {{W-|bno|rahon}}, {{W-|bno|dahon}}
* {{Z|ast}}: {{W+|ast|fueya|m}}
* {{Z|ask}}: {{W-|ask|pār}}
* {{Z|tay}}: {{W-|tay|abau}}
* {{Z|ay}}: {{W+|ay|laphi}}
* {{Z|ain}}: {{W-|ain|ハㇺ|tr=ham}}
* {{Z|az}}: {{W+|az|yarpaq}}
* {{Z|bdq}}: {{W-|bdq|hla}}
* {{Z|ban}}: {{W-|ban|don}}
* {{Z|eu}}: {{W+|eu|hosto}}, {{W+|eu|orri}}
* {{Z|ba}}: {{W-|ba|япраҡ}}
* {{Z|be}}: {{W-|be|ліст|n}}
* {{Z|bn}}: {{W+|bn|পাতা}}
* {{Z|bho}}: {{W-|bho|पान}}
* {{Z|bol}}: {{W-|bol|kumi rewe}}
* {{Z|br}}: {{W+|br|delienn|m}}
* {{Z|kxd}}: {{W-|kxd|daun}}
* {{Z|bug}}: {{W-|bug|daung}}
* {{Z|bg}}: {{W+|bg|лист|n}}, {{W+|bg|листо́|nt}}
* {{Z|my}}: {{W+|my|အရွက်}}
* {{Z|bua}}: {{W-|bua|набша}}, {{W-|bua|набшаһан}}, {{W-|bua|намаа}}
* {{Z|kac}}: {{W-|kac|lap}}
* {{Z|ccc}}: {{W-|ccc|chijpana}}
* {{Z|cjm}}: {{W-|cjm|ꨈꨶꨮꩉ}}, {{W-|cjm|ꨨꨤꨩ}}
* {{Z|cbk}}: {{W-|cbk|ohas}}
* {{Z|ce}}: {{W-|ce|гӏа}}
* {{Z|cs}}: {{W+|cs|list|n}}
* {{Z|chr}}: {{W-|chr|ᎤᎦᎶᎬ}}
* {{Z|ny}}: {{W-|ny|tsamba}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|葉|tr=jip6}}, {{W-|yue|葉子|tr=jip6 zi2}}
*: {{Z|dng}}: {{W-|dng|еезы}}, {{W-|dng|еер}}, {{W-|dng|езы}}
*: {{Z|hak}}: {{W-|hak|葉|tr=ya̍p}}
*: {{Z|cjy}}: {{W-|cjy|葉子|tr=ieh4 zeh}}
*: {{Z|cmn}}: {{W+|cmn|葉|tr=yè}}, {{W+|cmn|葉子|tr=yèzi}}
*: {{Z|cdo}}: {{W-|cdo|箬箬|tr=niŏh-niŏh}}
*: {{Z|nan}}: {{W+|nan|葉|tr=ia̍p}}, {{W+|nan|葉仔|tr=hio̍h-á}}
*: {{Z|wuu}}: {{W-|wuu|葉}}, {{W-|wuu|葉子}}
*: {{Z|hsn}}: {{W-|hsn|葉子|tr=ie6 zr}}
* {{Z|cv}}: {{W-|cv|ҫулҫӑ}}
* {{Z|dlm}}: {{W-|dlm|fualja|m}}
* {{Z|da}}: {{W+|da|blad|nt}}, {{W-|da|løv|nt}}
* {{Z|duu}}: {{W-|duu|vng'lvp}}
* {{Z|id}}: {{W+|id|daun}}
* {{Z|enq}}: {{W-|enq|yoko}}
* {{Z|ar}}: {{W-|ar|وَرَقَة|m}}
* {{Z|hy}}: {{W-|hy|տերեւ}}
* {{Z|myv}}: {{W-|myv|лопа}}
* {{Z|eo}}: {{W+|eo|folio}}
* {{Z|et}}: {{W+|et|leht}}
* {{Z|gez}}: {{W-|gez|ቈጽል}}
* {{Z|eve}}: {{W-|eve|эбдэнрэ}}
* {{Z|evn}}: {{W-|evn|авданна}}
* {{Z|ee}}: {{W-|ee|aŋgba}}
* {{Z|fa}}: {{W+|fa|برگ|tr=barg}}
* {{Z|fo}}: {{W-|fo|blað|nt}}
* {{Z|fj}}: {{W+|fj|drau}}
* {{Z|fi}}: {{W+|fi|lehti}}
* {{Z|fon}}: {{W-|fon|ama}}
* {{Z|frp}}: {{W-|frp|fôlye|m}}
* {{Z|fro}}: {{W-|fro|fueille|m}}
* {{Z|fr}}: {{W+|fr|feuille|m}}
* {{Z|fur}}: {{W-|fur|fuee|m}}
* {{Z|stq}}: {{W-|stq|Blääd|nt}}
* {{Z|fy}}: {{W-|fy|blêd}}
* {{Z|ff}}:
*: Latînî: {{W-|ff|haako}}, {{W-|ff|kaakol}}
*: Adlamî: {{W-|ff|𞤸𞤢𞥄𞤳𞤮}}, {{W-|ff|𞤳𞤢𞥄𞤳𞤮𞤤}}
* {{Z|fuy}}: {{W-|fuy|hutu}}
* {{Z|gd}}: {{W-|gd|duille|m}}, {{W-|gd|duilleag|m}}
* {{Z|gl}}: {{W+|gl|folla|m}}
* {{Z|glk}}: {{W-|glk|ولگ}}
* {{Z|gu}}: {{W-|gu|પાન|m}}, {{W-|gu|પર્ણ|nt}}, {{W-|gu|પાંદડું|nt}}, {{W-|gu|દલ}}
* {{Z|ka}}: {{W+|ka|ფოთოლი}}
* {{Z|gn}}: {{W+|gn|togue}}
* {{Z|gwi}}: {{W-|gwi|chʼatʼan}}
* {{Z|ht}}: {{W-|ht|fèy}}
* {{Z|haw}}: {{W-|haw|lau}}
* {{Z|ha}}: {{W+|ha|ganye}}, {{W-|ha|warƙa}}
* {{Z|mba}}: {{W-|mba|dahon}}
* {{Z|hi}}: {{W+|hi|पत्ता|n}}, {{W+|hi|पत्ती|m}}
* {{Z|ho}}: {{W-|ho|raurau}}
* {{Z|hil}}: {{W-|hil|dahon}}
* {{Z|meu}}: {{W-|meu|rau}}
* {{Z|mww}}: {{W-|mww|nplooj}}
* {{Z|nl}}: {{W+|nl|blad|nt}}
* {{Z|hop}}: {{W-|hop|nàapi}}
* {{Z|he}}: {{W+|he|עָלֶה|n|tr=alé}}
* {{Z|io}}: {{W+|io|folio}}
* {{Z|ig}}: {{W-|ig|akwụkwọ}}
* {{Z|inz}}: {{W-|inz|qap}}
* {{Z|ang}}: {{W+|ang|lēaf|nt}}
* {{Z|en}}: {{W+|en|leaf}}
* {{Z|izh}}: {{W-|izh|lehti}}
* {{Z|ia}}: {{W-|ia|folio}}
* {{Z|iu}}: {{W-|iu|ᐊᑭᕈᐊᕈᖅ}}
* {{Z|ill}}: {{W-|ill|raun}}
* {{Z|ga}}: {{W+|ga|duilleog|m}}, {{W+|ga|bileog|m}}
* {{Z|it}}: {{W+|it|foglia|m}}
* {{Z|ium}}: {{W-|ium|normh}}
* {{Z|is}}: {{W+|is|lauf|nt}}, {{W+|is|laufblað|nt}}
* {{Z|ja}}: {{W+|ja|葉|tr=は, ha}}, {{W+|ja|葉っぱ|tr=はっぱ, happa}}, {{W+|ja|木の葉|tr=このは, konoha}}
* {{Z|jra}}: {{W-|jra|hla}}
* {{Z|kaw}}: {{W-|kaw|ron}}
* {{Z|jv}}: {{W+|jv|godhong}}, {{W-|jv|ron}}
* {{Z|kl}}: {{W-|kl|pilu}}
* {{Z|bsh}}: {{W-|bsh|por}}
* {{Z|kn}}: {{W+|kn|ಎಲೆ}}
* {{Z|pam}}: {{W-|pam|bulung}}
* {{Z|krl}}: {{W-|krl|lehti}}
* {{Z|csb}}: {{W-|csb|lëst}}
* {{Z|ca}}: {{W+|ca|fulla|m}}
* {{Z|qu}}: {{W-|qu|raphi}}, {{W-|qu|llaqhi}}
* {{Z|kha}}: {{W-|kha|sla}}
* {{Z|kzg}}: {{W-|kzg|葉|tr=ぱー, pā}}
* {{Z|ky}}: {{W+|ky|жалбырак}}
* {{Z|ki}}: {{W-|ki|ithangũ|c5}}
* {{Z|si}}: {{W-|si|කොළේ}}, {{W-|si|කොළය}}
* {{Z|kyi}}: {{W-|kyi|dun}}
* {{Z|koi}}: {{W-|koi|кор}}
* {{Z|swb}}: {{W-|swb|wani|c11|c6}}
* {{Z|kok}}: {{W-|kok|पाल्लो|tr=pāllo}}
* {{Z|ko}}: {{W+|ko|잎}}
* {{Z|co}}: {{W+|co|foglia|m}}
* {{Z|cr}}:
*: {{Z|crk}}: {{W-|crk|nīpiy}}
* {{Z|xug}}: {{W-|xug|葉|tr=ぱー, phā}}
* {{Z|lad}}: {{W-|lad|foja|m}}, {{W-|lad|yaprak|n}}
* {{Z|lkt}}: {{W-|lkt|wahpe}}, {{W-|lkt|ape}}
* {{Z|ltg}}: {{W-|ltg|lopa|m}}
* {{Z|la}}: {{W+|la|folium|nt}}, {{W-|la|frons|m}}
* {{Z|lv}}: {{W+|lv|lapa|m}}
* {{Z|lo}}: {{W-|lo|ໃບ}}, {{W+|lo|ໃບໄມ້}}
* {{Z|ln}}: {{W-|ln|nkásá|c9|c10}}, {{W-|ln|lokásá|c11|c10}}
* {{Z|lij}}: {{W-|lij|féuggia|m}}
* {{Z|li}}: {{W+|li|louf|nt}}
* {{Z|lt}}: {{W+|lt|lapas|n}}
* {{Z|lmo}}: {{W-|lmo|foeuja|m}}, {{W-|lmo|fòia|m}}
* {{Z|lg}}: {{W-|lg|ekikoola}}
* {{Z|luy}}: {{W-|luy|lisafu}}
* {{Z|lb}}: {{W-|lb|Blat|nt}}
* {{Z|mhn}}: {{W-|mhn|lap|nt}}
* {{Z|mdh}}: {{W-|mdh|laun}}
* {{Z|mk}}: {{W-|mk|лист|n}}
* {{Z|mg}}: {{W+|mg|ravina}}, {{W+|mg|ravina}}
* {{Z|ml}}: {{W+|ml|ഇല}}
* {{Z|ms}}: {{W+|ms|daun}}
* {{Z|mt}}: {{W-|mt|werqa|m}}
* {{Z|mnc}}: {{W-|mnc|ᠠᠪᡩᠠᡥᠠ}}
* {{Z|gv}}: {{W-|gv|duillag|m}}
* {{Z|mns-nor}}: {{W-|mns-nor|лӯпта}}
* {{Z|mi}}: {{W+|mi|rau}}, {{W-|mi|tawhera}}
* {{Z|mrw}}: {{W-|mrw|ra'on}}
* {{Z|mr}}: {{W-|mr|पर्ण|nt}}, {{W+|mr|पत्र|nt}}, {{W+|mr|दल|nt}}
* Marî:
*: {{Z|mhr}}: {{W-|mhr|лышташ}}
*: {{Z|mrj}}: {{W-|mrj|ӹлӹштӓш}}
* {{Z|gun}}: {{W-|gun|ogue}}
* {{Z|hu}}: {{W+|hu|levél}}, {{W+|hu|falevél}}
* {{Z|mel}}: {{W-|mel|daun}}
* {{Z|egy}}: {{W-egy|gꜣbt|h=g-A-b-t-Hn:Z2ss}}
* {{Z|mvi}}: {{W-|mvi|葉|tr=ぱー, pā}}
* {{Z|lus}}: {{W-|lus|hnah}}
* {{Z|min}}: {{W-|min|daun}}
* {{Z|mwl}}: {{W-|mwl|fuolha|m}}
* {{Z|xpq}}: {{W-|xpq|wunipaq}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|навч}}
*: Mongolî: {{W-|mn|ᠨᠠᠪᠴᠢ}}
* {{Z|mnw}}: {{W-|mnw|သၠ|tr=hlaˀ}}
* {{Z|mtq}}: {{W-|mtq|lả}}
* {{Z|nah}}: {{W+|nah|izhuatl}}
* {{Z|gld}}: {{W-|gld|хабдата}}
* {{Z|nv}}: {{W-|nv|atʼąąʼ}}
* {{Z|nds}}:
*: {{Z|nds-de}}: {{W-|nds-de|Blatt|nt}}
* {{Z|ne}}: {{W+|ne|पात}}
* {{Z|ncb}}: {{W-|ncb|dai}}
* {{Z|nrf}}: {{W-|nrf|fielle|m}}, {{W-|nrf|fieille|m}}, {{W-|nrf|fuule|m}}, {{W-|nrf|fiëly|m}}
* {{Z|no}}:
*: {{Z|nb}}: {{W+|nb|blad|nt}}, {{W+|nb|løv|nt}}
*: {{Z|nn}}: {{W-|nn|blad|nt}}, {{W-|nn|lauv|nt}}
* {{Z|oj}}: {{W-|oj|aniibiishibag}}, {{W-|oj|aniibiishibagoon|p}}, {{W-|oj|aniibiish}}, {{W-|oj|aniibiishan|p}}, {{W-|oj|ᐊᓂᐱᐦᔑᐸᐟ|tr=aniibiishibag}}, {{W-|oj|ᐊᓂᐱᐦᔑᐸᑯᐣ|p|tr=aniibiishibagoon}}, {{W-|oj|ᐊᓂᐱᐦᐡ|tr=aniibiish}}, {{W-|oj|ᐊᓂᐱᐦᔕᐣ|p|tr=aniibiishan}}
* {{Z|okn}}: {{W-|okn|葉|tr=はー, fā}}
* {{Z|ryu}}: {{W-|ryu|葉|tr=ふぁー, fā}}
* {{Z|oc}}: {{W+|oc|fuèlha|m}}
* {{Z|one}}: {{W-|one|onláhte̲’}}
* {{Z|or}}: {{W+|or|ପତ୍ର}}
* {{Z|osa}}: {{W-|osa|žąąpé}}
* {{Z|os}}: {{W-|os|сыф}}
* {{Z|ota}}: {{W-|ota|یپراق|tr=yaprak}}
* {{Z|ug}}: {{W-|ug|يوپۇرماق}}, {{W-|ug|ياپراق}}
* {{Z|uz}}: {{W+|uz|yaproq}}, {{W+|uz|barg}}
* {{Z|pac}}: {{W-|pac|ula}}, {{W-|pac|ila}}
* {{Z|pau}}: {{W-|pau|llel}}
* Pali:
*: {{Z|pi}}: {{W-|pi|ပဏ္ဏ|nt}}
*: {{Z|pi}}: {{W-|pi|पण्ण|nt}}
*: {{Z|pi}}: {{W-|pi|បណ្ណ|nt}}
*: Latînî: {{W-|pi|paṇṇa|nt}}
*: {{Z|pi}}: {{W-|pi|පණ්ණ|nt}}
*: {{Z|pi}}: {{W-|pi|ปณฺณ|nt}}
* {{Z|pap}}: {{W-|pap|foya}}
* {{Z|bxd}}: {{W-|bxd|a³¹faʔ⁵⁵}}, {{W-|bxd|sak⁵⁵ faʔ⁵⁵}}
* {{Z|ps}}: {{W+|ps|پاڼه|m|tr=pâṇa}}
* {{Z|pms}}: {{W-|pms|feuja|m}}
* {{Z|ppl}}: {{W-|ppl|iswat}}, {{W-|ppl|izhuat}}
* {{Z|pdt}}: {{W-|pdt|Blaut|nt}}
* {{Z|pl}}: {{W+|pl|liść|n}}
* {{Z|pt}}: {{W+|pt|folha|m}}
* {{Z|prn}}: {{W-|prn|pārag}}
* {{Z|pa}}: {{W-|pa|ਪੱਤਾ|n}}
* {{Z|kk}}: {{W-|kk|жапырақ}}
* {{Z|rap}}: {{W-|rap|rua}}
* {{Z|rhg}}: {{W-|rhg|fata}}
* {{Z|rgn}}: {{W-|rgn|fója|m}}
* {{Z|rm}}: {{W-|rm|fegl}}
* {{Z|rom}}: {{W-|rom|patrin|m}}
* {{Z|ro}}: {{W+|ro|frunză|m}}
* {{Z|ru}}: {{W+|ru|лист|n}}, plural for this sense: {{W+|ru|ли́стья|n-p}}
* {{Z|ksw}}: {{W-|ksw|သ့ၣ်လၣ်}}
* {{Z|ssy}}: {{W-|ssy|dharhaa}}
* {{Z|se}}: {{W-|se|lasta}}
* {{Z|sm}}: {{W-|sm|lau}}
* {{Z|sa}}: {{W+|sa|पर्ण|tr=parṇá|nt}}, {{W+|sa|पत्र|nt}}
* {{Z|sc}}: {{W-|sc|fògia|m}}
* {{Z|ceb}}: {{W-|ceb|dahon}}
* {{Z|sea}}: {{W-|sea|sela}}
* {{Z|scn}}: {{W+|scn|fogghia|m}}
* {{Z|sd}}: {{W-|sd|پن|n|tr=panu|cuda=پَنُ}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|лист|n}}, {{W-|sh|лиска|m}}
*: Latînî: {{W+|sh|list|n}}, {{W+|sh|liska|m}}
* {{Z|cu}}:
*: Kirîlî: {{W-|cu|листъ|n}}
*: Glagolîtîk: {{W-|cu|ⰾⰹⱄⱅⱏ|n}}
* {{Z|orv}}: {{W-|orv|листъ|n}}
* {{Z|sk}}: {{W+|sk|list|n}}
* {{Z|sl}}: {{W+|sl|list|n}}
* {{Z|zlw-slv}}: {{W-|zlw-slv|lȧ̃st|n}}
* {{Z|so}}: {{W+|so|caleen|m}}
* Sorbî:
*: {{Z|dsb}}: {{W-|dsb|list|n}}
*: {{Z|hsb}}: {{W-|hsb|list|n}}
* {{Z|es}}: {{W+|es|hoja|m}}
* {{Z|su}}: {{W+|su|daun}}
* {{Z|sw}}: {{W+|sw|jani|c5|c6}}, {{W+|sw|msahafu|c3|c4}}
* {{Z|sv}}: {{W+|sv|blad|nt}}, {{W+|sv|löv|nt}}
* {{Z|shn}}: {{W-|shn|မႂ်}}, {{W-|shn|ဝႂ်}}
* {{Z|zdj}}: {{W-|zdj|wani|c11|c10}}
* {{Z|sn}}: {{W-|sn|shizha}}
* {{Z|tg}}: {{W+|tg|барг}}
* {{Z|tl}}: {{W+|tl|dahon}}
* {{Z|tly}}: {{W-|tly|لیو}}
* {{Z|ta}}: {{W+|ta|இலை}}
* {{Z|twf}}: {{W-|twf|ə̂na}}
* {{Z|roa-tar}}: {{W-|roa-tar|fogghie|m}}
* {{Z|rif}}: {{W-|rif|afar|n}}, {{W-|rif|tifrešt|m}}
* {{Z|tsg}}: {{W-|tsg|dahun}}
* {{Z|th}}: {{W+|th|ใบ}}, {{W+|th|ใบไม้}}
* {{Z|te}}: {{W+|te|ఆకు}}
* {{Z|tzm}}: {{W-|tzm|ⵉⴼⴻⵔ|n}}
* {{Z|tea}}: {{W-|tea|sela}}
* {{Z|tt}}: {{W+|tt|яфрак}}
* {{Z|tet}}: {{W-|tet|roo}}
* {{Z|tr}}: {{W+|tr|yaprak}}
* {{Z|tk}}: {{W-|tk|ýaprak}}
* {{Z|bo}}: {{W-|bo|ལོ་མ།}}
* {{Z|tli}}: {{W-|tli|kayaaní}}
* {{Z|tpi}}: {{W-|tpi|lip}}
* {{Z|tkn}}: {{W-|tkn|葉|tr=はー, hā}}
* {{Z|xto}}: {{W-|xto|pält}}
* {{Z|txb}}: {{W-|txb|pilta}}
* {{Z|trm}}: {{W-|trm|påṭ}}
* {{Z|tcy}}: {{W-|tcy|ಅಡಿಪಿರೆ}}
* {{Z|tvl}}: {{W-|tvl|lau}}
* {{Z|tpw}}: {{W-|tpw|oba}}
* {{Z|udi}}: {{W-|udi|хазал}}
* {{Z|udm}}: {{W-|udm|куар}}
* {{Z|ur}}: {{W-|ur|پتی|m|tr=patti}}
* {{Z|uk}}: {{W+|uk|лист|n}}
* {{Z|vec}}: {{W+|vec|foja|m}}, {{W-|vec|fogia|m}}
* {{Z|vep}}: {{W-|vep|leht}}
* {{Z|vi}}: {{W+|vi|lá}}
* {{Z|vo}}: {{W+|vo|bled}}
* {{Z|vor}}: {{W-|vor|leht'}}
* {{Z|vot}}: {{W-|vot|lehti}}
* {{Z|wbk}}: {{W-|wbk|poṭ}}
* {{Z|wa}}: {{W+|wa|foye|m}}
* {{Z|war}}: {{W-|war|dáhon}}
* {{Z|cy}}: {{W+|cy|deilen|m}}
* {{Z|wym}}: {{W-|wym|błot|nt}}
* {{Z|wo}}: {{W+|wo|xob}}
* {{Z|km}}: {{W+|km|ស្លឹក}}, {{W-|km|ស្លឹកឈើ}}
* {{Z|xh}}: {{W-|xh|igqabi|c5|c6}}
* {{Z|rys}}: {{W-|rys|葉|tr=ぱー, pā}}
* {{Z|sah}}: {{W-|sah|сэбирдэх}}
* {{Z|yag}}: {{W-|yag|Suka}}
* {{Z|yi}}: {{W-|yi|בלאַט|n|m}}
* {{Z|yoi}}: {{W-|yoi|葉|tr=はー, hā}}
* {{Z|yox}}: {{W-|yox|葉|tr=ぱー, pā}}
* {{Z|yo}}: {{W-|yo|ewé}}
* {{Z|el}}: {{W+|el|φύλλο|nt}}
*: Kevn: {{W-|grc|φύλλον|nt}}, {{W-|grc|πέταλον|nt}}
* {{Z|zea}}: {{W-|zea|blad|nt}}
* {{Z|za}}: {{W-|za|mbaw}}
* {{Z|zu}}: {{W+|zu|ikhasi|c5|c6}}, {{W+|zu|iqabi|c5|c6}}
{{werger-bin}}
:{{werger çavkanî|en|leaf|beş=Ev qismê Wergerê|oldid=76702326}}
{{werger-ser|per, kaxez, weraqe, belgename}}
* {{Z|de}}: {{W+|de|Laub}} {{n}}, {{W+|de|Seite}} {{m}}, {{W+|de|Wedel|guman=erê}} {{n}}
* {{Z|fa}}: {{W+|fa|برگ}}, {{W+|fa|سند}}, {{W+|fa|صفحه}}, {{W+|fa|برگه|guman=erê}}, {{W-|fa|شراره آتش|guman=erê}}, {{W+|fa|کاغذ|guman=erê}}, {{W+|fa|مدرک|guman=erê}}
* {{Z|en}}: {{W+|en|covey}}, {{W+|en|foliage}}, {{W+|en|frond}}, {{W+|en|gleed}}, {{W+|en|platoon}}, {{W+|en|file}}, {{W+|en|phyllo-}}
* {{Z|tr}}: {{W+|tr|belge}}, {{W+|tr|çalkantı}}, {{W+|tr|çapak}}, {{W+|tr|lahza|guman=erê}}
{{werger-bin}}
=== Navdêr 2 ===
[[Wêne:Embers 01.JPG|thumb|250px|pel (2)]]
{{navdêr|ku|z=n}}
# [[pêt]], <br>[[parçe]]yên [[agir]]î yên ji [[pirt]]ên [[dar]]î yan [[kumir]]ê <br>(yên ku agirî girtine û dişewitin lê hê nebûne [[xwelî]])
==== Herwiha ====
* {{g|ku|pêlox}}
* {{g|ku|pêreng}}
* {{g|ku|piring}}
* {{g|ku|piloxt}}
==== Bi alfabeyên din ====
* {{ku-ar|پهل}}
==== Etîmolojî ====
Herwiha [[piring]], [[pêreng]], ji {{ji|ine-pro|ku|-}} *[[péh₂ur]] ([[agir]]), hevreha çekî [[pýř]] (pel), {{hv|grc|πῦρ}} (pûr: agir > kurdî [[pîroman]]), [[toxarî]] A ''por'' (agir), toxarî B ''puwar'' (agir), hîtîtî ''paḫḫur'' ([[agir]]), danmarkî / norwecî / {{hv|sv|fyr}} (agir), îngilîzî [[fire]] (agir), {{hv|hy|հուր}} (hur: agir)...
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Glut}} {{m}}
* {{Z|zh}}:
*: [[mandarînî]]: {{W+|cmn|餘燼|sc=Hani|xs=Mandarin}}, {{W+|cmn|余烬|tr=yújìn|sc=Hani|xs=Mandarin}}
* {{Z|ar}}: {{W-|ar|جمرة|tr=cemre}}
* {{Z|hy}}: {{W-|hy|մարմրող ածուխ|tr=marmroġ açux}}
* {{Z|eo}}: {{W-|eo|braĝo|xs=Esperanto}}, {{W-|eo|ardaĵo|xs=Esperanto}}
* {{Z|fa}}: {{W+|fa|شعله|sc=fa-Arab}}
* {{Z|fi}}: {{W+|fi|kekäle}}
* {{Z|fr}}: {{W+|fr|braise}} {{m}}
* {{Z|ka}}: {{W-|ka|მღვივარი ნახშირი|tr=mġvivari naxširi}}, {{W-|ka|ცხელი ნაცარი|tr=tsxeli natsari}}
* {{Z|nl}}: {{W+|nl|sintel}}
* {{Z|io}}: {{W+|io|brezo}}
* {{Z|en}}: {{W+|en|embers}}, {{W+|en|ember}}, {{W+|en|bracteole|guman=erê}}, {{W+|en|bractlet|guman=erê}}, {{W+|en|carbuncle|guman=erê}}, {{W+|en|fire-brand|guman=erê}}, {{W+|en|leafage|guman=erê}}, {{W-|en|live coal|guman=erê}}, {{W+|en|phyllome|guman=erê}}, {{W+|en|cigarette paper|guman=erê}}
* {{Z|it}}: {{W+|it|brace}} {{m}}
* {{Z|ca}}: {{W+|ca|brasa}} {{m}}
* {{Z|la}}: {{W+|la|favilla}} {{m}}
* {{Z|hu}}: {{W+|hu|zsarátnok}}; [[izzó fa]]([[darab]])/[[széndarab]], {{W+|hu|parázs}}
* {{Z|ru}}: {{W+|ru|уголёк|tr=ugoljók}} {{n}}, {{W-|ru|tr=gorjáčaja zolá|горячая зола}} {{m}}
* {{Z|sh}}: {{W+|sh|žar}} {{n}}, {{W+|sh|žeravica}} {{m}}
* {{Z|es}}: {{W+|es|brasa}} {{m}}, {{W+|es|ascua}} {{m}}
* {{Z|th}}: {{W-|th|แสงไฟในเศษฟืน|tr=săeng fai nai sèt feun}}, {{W-|th|ถ่านที่ยังคุอยู่|tr=tàan têe yang kóo yòo}}, {{W-|th|เถ้าที่ยังคุกกรุ่นอยู่|tr=tâo têe yang kóok gròon yòo}}
* {{Z|tr}}: {{W+|tr|kor}}, {{W+|tr|köz}}, {{W+|tr|levha|guman=erê}}, {{W+|tr|manga|guman=erê}}, {{W+|tr|sarma|guman=erê}}, {{W+|tr|takım|guman=erê}}, {{W+|tr|talaş|guman=erê}}, {{W+|tr|talaz|guman=erê}}, {{W+|tr|tim|guman=erê}}, {{W+|tr|titrek kavak|guman=erê}}, {{W+|tr|varak|guman=erê}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=?}}
# [[kelûpel]], [[tişt]], [[hûrûmûr]]
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|item}}, {{W+|en|goods}}, {{W+|en|wares}}, {{W+|en|products}}
{{werger-bin}}
== {{ziman|zza}} ==
=== Navdêr ===
{{navdêr|zza}}
# [[pel]]
== {{ziman|gl}} ==
=== Navdêr ===
{{navdêr|gl|z=m}}
# {{f|gl|anatomî}} [[çerm#ku|çerm]]
== {{ziman|oc}} ==
=== Navdêr ===
{{navdêr|oc|z=n}}
# {{f|oc|anatomî}} [[mû#ku|mû]], [[pûrt#ku|pûrt]], [[pirç#ku|pirç]]
== {{ziman|rm}} ==
=== Navdêr ===
{{navdêr|rm}}
# {{f|rm|anatomî}} [[çerm#ku|çerm]]
3o46l6xc82smgqskgdykd9bf84cxnf3
6241663
6241662
2026-07-11T20:31:59Z
Wikihez
7344
/* Navdêr 2 */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin
6241663
wikitext
text/x-wiki
{{binêre herwiha/pel}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA|pʰɛl}}
* {{ku-kîte}}
=== Navdêr 1 ===
{{ku-tewîn-nav|pel|nêr}}
[[Wêne:Leaf 1 web.jpg|thumb|pel (1)]]
{{navdêr|ku|z=n}}, {{p-ya req}}
# {{maneid|ku|riwek}} [[parçe|Parçe]]yên [[çeq]]ên [[dar]]an ve [[şên]] dibin. ([[pêşî]] ji [[bişkoj]]an [[pişkivîn|dipişkivin]], [[paşî]] [[kesk]] dibin û [[talî|taliyê]] [[beyîn|dibeyin]] anku [[zer]] dibin û [[werîn|diwerin]] anku [[weşîn|diweşin]])
#: {{hevmane|ku|belçim|belçîm|bilçik|belçûm|pelçim|pelçîm|pelçûm}}
# [[per]], [[kaxez]], [[weraqe]], [[belgename]]
==== Bi alfabeyên din ====
* {{ku-ar|پەل}}
==== Ji wêjeya klasîk ====
* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Ah-i bêgavê ji dil tên me ji pêta di ceger</br>Bes tu bêfeyde nesîhet ke me dil bûye '''pelek'''}}
==== Herwiha ====
{{kol3|ku|cure=Herwiha|sernav = [https://twitter.com/wikiferheng/status/1710338730089689440 Çavkanî]
| {{hw|ku|pelg||Sirûc|Bîraçik|Xelfetî}}
| {{hw|ku|pel||Mêrdîn|Sêwreg|Amed|Pasûr|Çewlîg|Bazîd}}
| {{hw|ku|pelçim||Botan}}
| {{hw|ku|belg||Dîgor|Agirî|Wan}}
| {{hw|ku|belçim||Dêrsim|Serhed}}
| {{hw|ku|pelç||Hewag}}
| {{hw|ku|per||Semsûr}}
}}
==== Bide ber ====
{{stûn|
* {{g|ku|pell}}
* {{g|ku|pal}}
* {{g|ku|pêl}}
* {{g|ku|pil}}
* {{g|ku|pîl}}
* {{g|ku|pol}}
* {{g|ku|pul}}
* {{g|ku|pûl}}
* {{g|ku|bel}}
}}
==== Jê ====
{{kol3|ku|cure=Jê
|pel girtin<q:lêker>
|pelgirtin<q:navdêr>
|pelçûn<q:navdêr>
}}
==== Etîmolojî ====
Hevreha şêxbizinî ''[[welg]]'', zazakî ''[[velg]]''
* {{ji|ine-pro|ku|-}}: *'''welə'''- ("hirî, pûrt") > *'''wolko'''- ("mû, hirî, pûrt; giya; daristan")
:*{{ji|ira-pro||-}}: *'''warka'''- ("belg, pel")
::{{ae}}: '''verke'''- ("belg, pel")
::{{xpr}}: '''wrgr''' ("belg, pel")
::{{pal}}: '''werg ''' ("belg, pel")
::{{sog}}: '''wrkr ''' ("belg, pel")
::{{fa}}: '''berg''' ("belg, pel")
::{{mzn}}: '''verek''' ("belg, pel")
::{{ku}}: '''belg > pelg > pel'''
::{{zza}}: '''[[velg]]''' ("belg, pel")
:{{sa}}: '''velke'''- ("[[per]], [[bask]]") ...
:{{la}}: '''vellus'''- ("hirî, pûrt")
:{{de}}: '''Wolle'''- ("hirî, pûrt")
:{{en}}: '''wool'''- ("hirî, pûrt")
;{{biçûk|Çavkanî:
* {{Horn|r=47}}
* {{Lubotsky|r=98}}
* {{Pokorny|r=1139}}
}}
==== Bi zaravayên din ====
* soranî/erdelanî: gella, pelk
* zazakî/kirmanckî: pel, pelçim, pure, velg,
* kelhûrî/feylî/şêxbizinî: welg, welneg, werg, belg, berg, pelg
* hewramî/şebekî: welg
==== Werger ====
{{werger-ser|riwek|id=riwek}}
* {{Z|ab}}: {{W-|ab|абӷьы}}
* {{Z|ace}}: {{W-|ace|ôn}}
* {{Z|ady}}: {{W-|ady|тхьэпкӏэ}}
* {{Z|aa}}: {{W-|aa|dalaa}}
* {{Z|af}}: {{W+|af|blaar}}
* {{Z|akl}}: {{W-|akl|dahon}}
* {{Z|sq}}: {{W+|sq|gjethe|m-p}}
* {{Z|pdc}}: {{W-|pdc|Blatt|nt}}
* {{Z|de}}: {{W+|de|Blatt|nt}}, {{W+|de|Laubblatt|nt}}
*: {{Z|gsw}}: {{W-|gsw|Blatt|nt}}
*: {{Z|gmw-cfr}}: {{W-|gmw-cfr|Blatt|nt}}
* {{Z|ryn}}: {{W-|ryn|葉|tr=はー, hā}}
* {{Z|ams}}: {{W-|ams|葉|tr=はー, hā}}
* {{Z|am}}: {{W-|am|ቅጠል}}
* {{Z|an}}: {{W+|an|fuella|m}}
* {{Z|arc}}:
*: {{Z|syc}}: {{W-|syc|ܛܪܦܐ|n|tr=ṭarpā}}
* {{Z|agj}}: {{W-|agj|ቅጠል|tr=qəțäl}}
* {{Z|rup}}: {{W-|rup|frãndzã|m}}, {{W-|rup|frundzã|m}}
* {{Z|as}}: {{W-|as|পাত|nt}}
* {{Z|bno}}: {{W-|bno|rahon}}, {{W-|bno|dahon}}
* {{Z|ast}}: {{W+|ast|fueya|m}}
* {{Z|ask}}: {{W-|ask|pār}}
* {{Z|tay}}: {{W-|tay|abau}}
* {{Z|ay}}: {{W+|ay|laphi}}
* {{Z|ain}}: {{W-|ain|ハㇺ|tr=ham}}
* {{Z|az}}: {{W+|az|yarpaq}}
* {{Z|bdq}}: {{W-|bdq|hla}}
* {{Z|ban}}: {{W-|ban|don}}
* {{Z|eu}}: {{W+|eu|hosto}}, {{W+|eu|orri}}
* {{Z|ba}}: {{W-|ba|япраҡ}}
* {{Z|be}}: {{W-|be|ліст|n}}
* {{Z|bn}}: {{W+|bn|পাতা}}
* {{Z|bho}}: {{W-|bho|पान}}
* {{Z|bol}}: {{W-|bol|kumi rewe}}
* {{Z|br}}: {{W+|br|delienn|m}}
* {{Z|kxd}}: {{W-|kxd|daun}}
* {{Z|bug}}: {{W-|bug|daung}}
* {{Z|bg}}: {{W+|bg|лист|n}}, {{W+|bg|листо́|nt}}
* {{Z|my}}: {{W+|my|အရွက်}}
* {{Z|bua}}: {{W-|bua|набша}}, {{W-|bua|набшаһан}}, {{W-|bua|намаа}}
* {{Z|kac}}: {{W-|kac|lap}}
* {{Z|ccc}}: {{W-|ccc|chijpana}}
* {{Z|cjm}}: {{W-|cjm|ꨈꨶꨮꩉ}}, {{W-|cjm|ꨨꨤꨩ}}
* {{Z|cbk}}: {{W-|cbk|ohas}}
* {{Z|ce}}: {{W-|ce|гӏа}}
* {{Z|cs}}: {{W+|cs|list|n}}
* {{Z|chr}}: {{W-|chr|ᎤᎦᎶᎬ}}
* {{Z|ny}}: {{W-|ny|tsamba}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|葉|tr=jip6}}, {{W-|yue|葉子|tr=jip6 zi2}}
*: {{Z|dng}}: {{W-|dng|еезы}}, {{W-|dng|еер}}, {{W-|dng|езы}}
*: {{Z|hak}}: {{W-|hak|葉|tr=ya̍p}}
*: {{Z|cjy}}: {{W-|cjy|葉子|tr=ieh4 zeh}}
*: {{Z|cmn}}: {{W+|cmn|葉|tr=yè}}, {{W+|cmn|葉子|tr=yèzi}}
*: {{Z|cdo}}: {{W-|cdo|箬箬|tr=niŏh-niŏh}}
*: {{Z|nan}}: {{W+|nan|葉|tr=ia̍p}}, {{W+|nan|葉仔|tr=hio̍h-á}}
*: {{Z|wuu}}: {{W-|wuu|葉}}, {{W-|wuu|葉子}}
*: {{Z|hsn}}: {{W-|hsn|葉子|tr=ie6 zr}}
* {{Z|cv}}: {{W-|cv|ҫулҫӑ}}
* {{Z|dlm}}: {{W-|dlm|fualja|m}}
* {{Z|da}}: {{W+|da|blad|nt}}, {{W-|da|løv|nt}}
* {{Z|duu}}: {{W-|duu|vng'lvp}}
* {{Z|id}}: {{W+|id|daun}}
* {{Z|enq}}: {{W-|enq|yoko}}
* {{Z|ar}}: {{W-|ar|وَرَقَة|m}}
* {{Z|hy}}: {{W-|hy|տերեւ}}
* {{Z|myv}}: {{W-|myv|лопа}}
* {{Z|eo}}: {{W+|eo|folio}}
* {{Z|et}}: {{W+|et|leht}}
* {{Z|gez}}: {{W-|gez|ቈጽል}}
* {{Z|eve}}: {{W-|eve|эбдэнрэ}}
* {{Z|evn}}: {{W-|evn|авданна}}
* {{Z|ee}}: {{W-|ee|aŋgba}}
* {{Z|fa}}: {{W+|fa|برگ|tr=barg}}
* {{Z|fo}}: {{W-|fo|blað|nt}}
* {{Z|fj}}: {{W+|fj|drau}}
* {{Z|fi}}: {{W+|fi|lehti}}
* {{Z|fon}}: {{W-|fon|ama}}
* {{Z|frp}}: {{W-|frp|fôlye|m}}
* {{Z|fro}}: {{W-|fro|fueille|m}}
* {{Z|fr}}: {{W+|fr|feuille|m}}
* {{Z|fur}}: {{W-|fur|fuee|m}}
* {{Z|stq}}: {{W-|stq|Blääd|nt}}
* {{Z|fy}}: {{W-|fy|blêd}}
* {{Z|ff}}:
*: Latînî: {{W-|ff|haako}}, {{W-|ff|kaakol}}
*: Adlamî: {{W-|ff|𞤸𞤢𞥄𞤳𞤮}}, {{W-|ff|𞤳𞤢𞥄𞤳𞤮𞤤}}
* {{Z|fuy}}: {{W-|fuy|hutu}}
* {{Z|gd}}: {{W-|gd|duille|m}}, {{W-|gd|duilleag|m}}
* {{Z|gl}}: {{W+|gl|folla|m}}
* {{Z|glk}}: {{W-|glk|ولگ}}
* {{Z|gu}}: {{W-|gu|પાન|m}}, {{W-|gu|પર્ણ|nt}}, {{W-|gu|પાંદડું|nt}}, {{W-|gu|દલ}}
* {{Z|ka}}: {{W+|ka|ფოთოლი}}
* {{Z|gn}}: {{W+|gn|togue}}
* {{Z|gwi}}: {{W-|gwi|chʼatʼan}}
* {{Z|ht}}: {{W-|ht|fèy}}
* {{Z|haw}}: {{W-|haw|lau}}
* {{Z|ha}}: {{W+|ha|ganye}}, {{W-|ha|warƙa}}
* {{Z|mba}}: {{W-|mba|dahon}}
* {{Z|hi}}: {{W+|hi|पत्ता|n}}, {{W+|hi|पत्ती|m}}
* {{Z|ho}}: {{W-|ho|raurau}}
* {{Z|hil}}: {{W-|hil|dahon}}
* {{Z|meu}}: {{W-|meu|rau}}
* {{Z|mww}}: {{W-|mww|nplooj}}
* {{Z|nl}}: {{W+|nl|blad|nt}}
* {{Z|hop}}: {{W-|hop|nàapi}}
* {{Z|he}}: {{W+|he|עָלֶה|n|tr=alé}}
* {{Z|io}}: {{W+|io|folio}}
* {{Z|ig}}: {{W-|ig|akwụkwọ}}
* {{Z|inz}}: {{W-|inz|qap}}
* {{Z|ang}}: {{W+|ang|lēaf|nt}}
* {{Z|en}}: {{W+|en|leaf}}
* {{Z|izh}}: {{W-|izh|lehti}}
* {{Z|ia}}: {{W-|ia|folio}}
* {{Z|iu}}: {{W-|iu|ᐊᑭᕈᐊᕈᖅ}}
* {{Z|ill}}: {{W-|ill|raun}}
* {{Z|ga}}: {{W+|ga|duilleog|m}}, {{W+|ga|bileog|m}}
* {{Z|it}}: {{W+|it|foglia|m}}
* {{Z|ium}}: {{W-|ium|normh}}
* {{Z|is}}: {{W+|is|lauf|nt}}, {{W+|is|laufblað|nt}}
* {{Z|ja}}: {{W+|ja|葉|tr=は, ha}}, {{W+|ja|葉っぱ|tr=はっぱ, happa}}, {{W+|ja|木の葉|tr=このは, konoha}}
* {{Z|jra}}: {{W-|jra|hla}}
* {{Z|kaw}}: {{W-|kaw|ron}}
* {{Z|jv}}: {{W+|jv|godhong}}, {{W-|jv|ron}}
* {{Z|kl}}: {{W-|kl|pilu}}
* {{Z|bsh}}: {{W-|bsh|por}}
* {{Z|kn}}: {{W+|kn|ಎಲೆ}}
* {{Z|pam}}: {{W-|pam|bulung}}
* {{Z|krl}}: {{W-|krl|lehti}}
* {{Z|csb}}: {{W-|csb|lëst}}
* {{Z|ca}}: {{W+|ca|fulla|m}}
* {{Z|qu}}: {{W-|qu|raphi}}, {{W-|qu|llaqhi}}
* {{Z|kha}}: {{W-|kha|sla}}
* {{Z|kzg}}: {{W-|kzg|葉|tr=ぱー, pā}}
* {{Z|ky}}: {{W+|ky|жалбырак}}
* {{Z|ki}}: {{W-|ki|ithangũ|c5}}
* {{Z|si}}: {{W-|si|කොළේ}}, {{W-|si|කොළය}}
* {{Z|kyi}}: {{W-|kyi|dun}}
* {{Z|koi}}: {{W-|koi|кор}}
* {{Z|swb}}: {{W-|swb|wani|c11|c6}}
* {{Z|kok}}: {{W-|kok|पाल्लो|tr=pāllo}}
* {{Z|ko}}: {{W+|ko|잎}}
* {{Z|co}}: {{W+|co|foglia|m}}
* {{Z|cr}}:
*: {{Z|crk}}: {{W-|crk|nīpiy}}
* {{Z|xug}}: {{W-|xug|葉|tr=ぱー, phā}}
* {{Z|lad}}: {{W-|lad|foja|m}}, {{W-|lad|yaprak|n}}
* {{Z|lkt}}: {{W-|lkt|wahpe}}, {{W-|lkt|ape}}
* {{Z|ltg}}: {{W-|ltg|lopa|m}}
* {{Z|la}}: {{W+|la|folium|nt}}, {{W-|la|frons|m}}
* {{Z|lv}}: {{W+|lv|lapa|m}}
* {{Z|lo}}: {{W-|lo|ໃບ}}, {{W+|lo|ໃບໄມ້}}
* {{Z|ln}}: {{W-|ln|nkásá|c9|c10}}, {{W-|ln|lokásá|c11|c10}}
* {{Z|lij}}: {{W-|lij|féuggia|m}}
* {{Z|li}}: {{W+|li|louf|nt}}
* {{Z|lt}}: {{W+|lt|lapas|n}}
* {{Z|lmo}}: {{W-|lmo|foeuja|m}}, {{W-|lmo|fòia|m}}
* {{Z|lg}}: {{W-|lg|ekikoola}}
* {{Z|luy}}: {{W-|luy|lisafu}}
* {{Z|lb}}: {{W-|lb|Blat|nt}}
* {{Z|mhn}}: {{W-|mhn|lap|nt}}
* {{Z|mdh}}: {{W-|mdh|laun}}
* {{Z|mk}}: {{W-|mk|лист|n}}
* {{Z|mg}}: {{W+|mg|ravina}}, {{W+|mg|ravina}}
* {{Z|ml}}: {{W+|ml|ഇല}}
* {{Z|ms}}: {{W+|ms|daun}}
* {{Z|mt}}: {{W-|mt|werqa|m}}
* {{Z|mnc}}: {{W-|mnc|ᠠᠪᡩᠠᡥᠠ}}
* {{Z|gv}}: {{W-|gv|duillag|m}}
* {{Z|mns-nor}}: {{W-|mns-nor|лӯпта}}
* {{Z|mi}}: {{W+|mi|rau}}, {{W-|mi|tawhera}}
* {{Z|mrw}}: {{W-|mrw|ra'on}}
* {{Z|mr}}: {{W-|mr|पर्ण|nt}}, {{W+|mr|पत्र|nt}}, {{W+|mr|दल|nt}}
* Marî:
*: {{Z|mhr}}: {{W-|mhr|лышташ}}
*: {{Z|mrj}}: {{W-|mrj|ӹлӹштӓш}}
* {{Z|gun}}: {{W-|gun|ogue}}
* {{Z|hu}}: {{W+|hu|levél}}, {{W+|hu|falevél}}
* {{Z|mel}}: {{W-|mel|daun}}
* {{Z|egy}}: {{W-egy|gꜣbt|h=g-A-b-t-Hn:Z2ss}}
* {{Z|mvi}}: {{W-|mvi|葉|tr=ぱー, pā}}
* {{Z|lus}}: {{W-|lus|hnah}}
* {{Z|min}}: {{W-|min|daun}}
* {{Z|mwl}}: {{W-|mwl|fuolha|m}}
* {{Z|xpq}}: {{W-|xpq|wunipaq}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|навч}}
*: Mongolî: {{W-|mn|ᠨᠠᠪᠴᠢ}}
* {{Z|mnw}}: {{W-|mnw|သၠ|tr=hlaˀ}}
* {{Z|mtq}}: {{W-|mtq|lả}}
* {{Z|nah}}: {{W+|nah|izhuatl}}
* {{Z|gld}}: {{W-|gld|хабдата}}
* {{Z|nv}}: {{W-|nv|atʼąąʼ}}
* {{Z|nds}}:
*: {{Z|nds-de}}: {{W-|nds-de|Blatt|nt}}
* {{Z|ne}}: {{W+|ne|पात}}
* {{Z|ncb}}: {{W-|ncb|dai}}
* {{Z|nrf}}: {{W-|nrf|fielle|m}}, {{W-|nrf|fieille|m}}, {{W-|nrf|fuule|m}}, {{W-|nrf|fiëly|m}}
* {{Z|no}}:
*: {{Z|nb}}: {{W+|nb|blad|nt}}, {{W+|nb|løv|nt}}
*: {{Z|nn}}: {{W-|nn|blad|nt}}, {{W-|nn|lauv|nt}}
* {{Z|oj}}: {{W-|oj|aniibiishibag}}, {{W-|oj|aniibiishibagoon|p}}, {{W-|oj|aniibiish}}, {{W-|oj|aniibiishan|p}}, {{W-|oj|ᐊᓂᐱᐦᔑᐸᐟ|tr=aniibiishibag}}, {{W-|oj|ᐊᓂᐱᐦᔑᐸᑯᐣ|p|tr=aniibiishibagoon}}, {{W-|oj|ᐊᓂᐱᐦᐡ|tr=aniibiish}}, {{W-|oj|ᐊᓂᐱᐦᔕᐣ|p|tr=aniibiishan}}
* {{Z|okn}}: {{W-|okn|葉|tr=はー, fā}}
* {{Z|ryu}}: {{W-|ryu|葉|tr=ふぁー, fā}}
* {{Z|oc}}: {{W+|oc|fuèlha|m}}
* {{Z|one}}: {{W-|one|onláhte̲’}}
* {{Z|or}}: {{W+|or|ପତ୍ର}}
* {{Z|osa}}: {{W-|osa|žąąpé}}
* {{Z|os}}: {{W-|os|сыф}}
* {{Z|ota}}: {{W-|ota|یپراق|tr=yaprak}}
* {{Z|ug}}: {{W-|ug|يوپۇرماق}}, {{W-|ug|ياپراق}}
* {{Z|uz}}: {{W+|uz|yaproq}}, {{W+|uz|barg}}
* {{Z|pac}}: {{W-|pac|ula}}, {{W-|pac|ila}}
* {{Z|pau}}: {{W-|pau|llel}}
* Pali:
*: {{Z|pi}}: {{W-|pi|ပဏ္ဏ|nt}}
*: {{Z|pi}}: {{W-|pi|पण्ण|nt}}
*: {{Z|pi}}: {{W-|pi|បណ្ណ|nt}}
*: Latînî: {{W-|pi|paṇṇa|nt}}
*: {{Z|pi}}: {{W-|pi|පණ්ණ|nt}}
*: {{Z|pi}}: {{W-|pi|ปณฺณ|nt}}
* {{Z|pap}}: {{W-|pap|foya}}
* {{Z|bxd}}: {{W-|bxd|a³¹faʔ⁵⁵}}, {{W-|bxd|sak⁵⁵ faʔ⁵⁵}}
* {{Z|ps}}: {{W+|ps|پاڼه|m|tr=pâṇa}}
* {{Z|pms}}: {{W-|pms|feuja|m}}
* {{Z|ppl}}: {{W-|ppl|iswat}}, {{W-|ppl|izhuat}}
* {{Z|pdt}}: {{W-|pdt|Blaut|nt}}
* {{Z|pl}}: {{W+|pl|liść|n}}
* {{Z|pt}}: {{W+|pt|folha|m}}
* {{Z|prn}}: {{W-|prn|pārag}}
* {{Z|pa}}: {{W-|pa|ਪੱਤਾ|n}}
* {{Z|kk}}: {{W-|kk|жапырақ}}
* {{Z|rap}}: {{W-|rap|rua}}
* {{Z|rhg}}: {{W-|rhg|fata}}
* {{Z|rgn}}: {{W-|rgn|fója|m}}
* {{Z|rm}}: {{W-|rm|fegl}}
* {{Z|rom}}: {{W-|rom|patrin|m}}
* {{Z|ro}}: {{W+|ro|frunză|m}}
* {{Z|ru}}: {{W+|ru|лист|n}}, plural for this sense: {{W+|ru|ли́стья|n-p}}
* {{Z|ksw}}: {{W-|ksw|သ့ၣ်လၣ်}}
* {{Z|ssy}}: {{W-|ssy|dharhaa}}
* {{Z|se}}: {{W-|se|lasta}}
* {{Z|sm}}: {{W-|sm|lau}}
* {{Z|sa}}: {{W+|sa|पर्ण|tr=parṇá|nt}}, {{W+|sa|पत्र|nt}}
* {{Z|sc}}: {{W-|sc|fògia|m}}
* {{Z|ceb}}: {{W-|ceb|dahon}}
* {{Z|sea}}: {{W-|sea|sela}}
* {{Z|scn}}: {{W+|scn|fogghia|m}}
* {{Z|sd}}: {{W-|sd|پن|n|tr=panu|cuda=پَنُ}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|лист|n}}, {{W-|sh|лиска|m}}
*: Latînî: {{W+|sh|list|n}}, {{W+|sh|liska|m}}
* {{Z|cu}}:
*: Kirîlî: {{W-|cu|листъ|n}}
*: Glagolîtîk: {{W-|cu|ⰾⰹⱄⱅⱏ|n}}
* {{Z|orv}}: {{W-|orv|листъ|n}}
* {{Z|sk}}: {{W+|sk|list|n}}
* {{Z|sl}}: {{W+|sl|list|n}}
* {{Z|zlw-slv}}: {{W-|zlw-slv|lȧ̃st|n}}
* {{Z|so}}: {{W+|so|caleen|m}}
* Sorbî:
*: {{Z|dsb}}: {{W-|dsb|list|n}}
*: {{Z|hsb}}: {{W-|hsb|list|n}}
* {{Z|es}}: {{W+|es|hoja|m}}
* {{Z|su}}: {{W+|su|daun}}
* {{Z|sw}}: {{W+|sw|jani|c5|c6}}, {{W+|sw|msahafu|c3|c4}}
* {{Z|sv}}: {{W+|sv|blad|nt}}, {{W+|sv|löv|nt}}
* {{Z|shn}}: {{W-|shn|မႂ်}}, {{W-|shn|ဝႂ်}}
* {{Z|zdj}}: {{W-|zdj|wani|c11|c10}}
* {{Z|sn}}: {{W-|sn|shizha}}
* {{Z|tg}}: {{W+|tg|барг}}
* {{Z|tl}}: {{W+|tl|dahon}}
* {{Z|tly}}: {{W-|tly|لیو}}
* {{Z|ta}}: {{W+|ta|இலை}}
* {{Z|twf}}: {{W-|twf|ə̂na}}
* {{Z|roa-tar}}: {{W-|roa-tar|fogghie|m}}
* {{Z|rif}}: {{W-|rif|afar|n}}, {{W-|rif|tifrešt|m}}
* {{Z|tsg}}: {{W-|tsg|dahun}}
* {{Z|th}}: {{W+|th|ใบ}}, {{W+|th|ใบไม้}}
* {{Z|te}}: {{W+|te|ఆకు}}
* {{Z|tzm}}: {{W-|tzm|ⵉⴼⴻⵔ|n}}
* {{Z|tea}}: {{W-|tea|sela}}
* {{Z|tt}}: {{W+|tt|яфрак}}
* {{Z|tet}}: {{W-|tet|roo}}
* {{Z|tr}}: {{W+|tr|yaprak}}
* {{Z|tk}}: {{W-|tk|ýaprak}}
* {{Z|bo}}: {{W-|bo|ལོ་མ།}}
* {{Z|tli}}: {{W-|tli|kayaaní}}
* {{Z|tpi}}: {{W-|tpi|lip}}
* {{Z|tkn}}: {{W-|tkn|葉|tr=はー, hā}}
* {{Z|xto}}: {{W-|xto|pält}}
* {{Z|txb}}: {{W-|txb|pilta}}
* {{Z|trm}}: {{W-|trm|påṭ}}
* {{Z|tcy}}: {{W-|tcy|ಅಡಿಪಿರೆ}}
* {{Z|tvl}}: {{W-|tvl|lau}}
* {{Z|tpw}}: {{W-|tpw|oba}}
* {{Z|udi}}: {{W-|udi|хазал}}
* {{Z|udm}}: {{W-|udm|куар}}
* {{Z|ur}}: {{W-|ur|پتی|m|tr=patti}}
* {{Z|uk}}: {{W+|uk|лист|n}}
* {{Z|vec}}: {{W+|vec|foja|m}}, {{W-|vec|fogia|m}}
* {{Z|vep}}: {{W-|vep|leht}}
* {{Z|vi}}: {{W+|vi|lá}}
* {{Z|vo}}: {{W+|vo|bled}}
* {{Z|vor}}: {{W-|vor|leht'}}
* {{Z|vot}}: {{W-|vot|lehti}}
* {{Z|wbk}}: {{W-|wbk|poṭ}}
* {{Z|wa}}: {{W+|wa|foye|m}}
* {{Z|war}}: {{W-|war|dáhon}}
* {{Z|cy}}: {{W+|cy|deilen|m}}
* {{Z|wym}}: {{W-|wym|błot|nt}}
* {{Z|wo}}: {{W+|wo|xob}}
* {{Z|km}}: {{W+|km|ស្លឹក}}, {{W-|km|ស្លឹកឈើ}}
* {{Z|xh}}: {{W-|xh|igqabi|c5|c6}}
* {{Z|rys}}: {{W-|rys|葉|tr=ぱー, pā}}
* {{Z|sah}}: {{W-|sah|сэбирдэх}}
* {{Z|yag}}: {{W-|yag|Suka}}
* {{Z|yi}}: {{W-|yi|בלאַט|n|m}}
* {{Z|yoi}}: {{W-|yoi|葉|tr=はー, hā}}
* {{Z|yox}}: {{W-|yox|葉|tr=ぱー, pā}}
* {{Z|yo}}: {{W-|yo|ewé}}
* {{Z|el}}: {{W+|el|φύλλο|nt}}
*: Kevn: {{W-|grc|φύλλον|nt}}, {{W-|grc|πέταλον|nt}}
* {{Z|zea}}: {{W-|zea|blad|nt}}
* {{Z|za}}: {{W-|za|mbaw}}
* {{Z|zu}}: {{W+|zu|ikhasi|c5|c6}}, {{W+|zu|iqabi|c5|c6}}
{{werger-bin}}
:{{werger çavkanî|en|leaf|beş=Ev qismê Wergerê|oldid=76702326}}
{{werger-ser|per, kaxez, weraqe, belgename}}
* {{Z|de}}: {{W+|de|Laub}} {{n}}, {{W+|de|Seite}} {{m}}, {{W+|de|Wedel|guman=erê}} {{n}}
* {{Z|fa}}: {{W+|fa|برگ}}, {{W+|fa|سند}}, {{W+|fa|صفحه}}, {{W+|fa|برگه|guman=erê}}, {{W-|fa|شراره آتش|guman=erê}}, {{W+|fa|کاغذ|guman=erê}}, {{W+|fa|مدرک|guman=erê}}
* {{Z|en}}: {{W+|en|covey}}, {{W+|en|foliage}}, {{W+|en|frond}}, {{W+|en|gleed}}, {{W+|en|platoon}}, {{W+|en|file}}, {{W+|en|phyllo-}}
* {{Z|tr}}: {{W+|tr|belge}}, {{W+|tr|çalkantı}}, {{W+|tr|çapak}}, {{W+|tr|lahza|guman=erê}}
{{werger-bin}}
=== Navdêr 2 ===
[[Wêne:Embers 01.JPG|thumb|250px|pel (2)]]
{{navdêr|ku|z=n}}
# [[parçe|Parçe]]yên [[agir]]î yên ji [[pirt]]ên [[dar]]î yan [[kumir]]ê yên ku agirî girtine û dişewitin lê hê nebûne [[xwelî]].
#: {{hevmane|ku|pêt}}
==== Bi alfabeyên din ====
* {{ku-ar|پهل}}
==== Herwiha ====
* {{g|ku|pêlox}}
* {{g|ku|pêreng}}
* {{g|ku|piring}}
* {{g|ku|piloxt}}
==== Etîmolojî ====
Herwiha [[piring]], [[pêreng]], ji {{ji|ine-pro|ku|*péh₂ur|t=[[agir]]}}.
Hevreha çekî [[pýř]] (pel), {{hv|grc|πῦρ}} (pûr: agir > kurdî [[pîroman]]), [[toxarî]] A ''por'' (agir), toxarî B ''puwar'' (agir), hîtîtî ''paḫḫur'' ([[agir]]), danmarkî / norwecî / {{hv|sv|fyr}} (agir), îngilîzî [[fire]] (agir), {{hv|hy|հուր}} (hur: agir)...
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Glut}} {{m}}
* {{Z|zh}}:
*: [[mandarînî]]: {{W+|cmn|餘燼|sc=Hani|xs=Mandarin}}, {{W+|cmn|余烬|tr=yújìn|sc=Hani|xs=Mandarin}}
* {{Z|ar}}: {{W-|ar|جمرة|tr=cemre}}
* {{Z|hy}}: {{W-|hy|մարմրող ածուխ|tr=marmroġ açux}}
* {{Z|eo}}: {{W-|eo|braĝo|xs=Esperanto}}, {{W-|eo|ardaĵo|xs=Esperanto}}
* {{Z|fa}}: {{W+|fa|شعله|sc=fa-Arab}}
* {{Z|fi}}: {{W+|fi|kekäle}}
* {{Z|fr}}: {{W+|fr|braise}} {{m}}
* {{Z|ka}}: {{W-|ka|მღვივარი ნახშირი|tr=mġvivari naxširi}}, {{W-|ka|ცხელი ნაცარი|tr=tsxeli natsari}}
* {{Z|nl}}: {{W+|nl|sintel}}
* {{Z|io}}: {{W+|io|brezo}}
* {{Z|en}}: {{W+|en|embers}}, {{W+|en|ember}}, {{W+|en|bracteole|guman=erê}}, {{W+|en|bractlet|guman=erê}}, {{W+|en|carbuncle|guman=erê}}, {{W+|en|fire-brand|guman=erê}}, {{W+|en|leafage|guman=erê}}, {{W-|en|live coal|guman=erê}}, {{W+|en|phyllome|guman=erê}}, {{W+|en|cigarette paper|guman=erê}}
* {{Z|it}}: {{W+|it|brace}} {{m}}
* {{Z|ca}}: {{W+|ca|brasa}} {{m}}
* {{Z|la}}: {{W+|la|favilla}} {{m}}
* {{Z|hu}}: {{W+|hu|zsarátnok}}; [[izzó fa]]([[darab]])/[[széndarab]], {{W+|hu|parázs}}
* {{Z|ru}}: {{W+|ru|уголёк|tr=ugoljók}} {{n}}, {{W-|ru|tr=gorjáčaja zolá|горячая зола}} {{m}}
* {{Z|sh}}: {{W+|sh|žar}} {{n}}, {{W+|sh|žeravica}} {{m}}
* {{Z|es}}: {{W+|es|brasa}} {{m}}, {{W+|es|ascua}} {{m}}
* {{Z|th}}: {{W-|th|แสงไฟในเศษฟืน|tr=săeng fai nai sèt feun}}, {{W-|th|ถ่านที่ยังคุอยู่|tr=tàan têe yang kóo yòo}}, {{W-|th|เถ้าที่ยังคุกกรุ่นอยู่|tr=tâo têe yang kóok gròon yòo}}
* {{Z|tr}}: {{W+|tr|kor}}, {{W+|tr|köz}}, {{W+|tr|levha|guman=erê}}, {{W+|tr|manga|guman=erê}}, {{W+|tr|sarma|guman=erê}}, {{W+|tr|takım|guman=erê}}, {{W+|tr|talaş|guman=erê}}, {{W+|tr|talaz|guman=erê}}, {{W+|tr|tim|guman=erê}}, {{W+|tr|titrek kavak|guman=erê}}, {{W+|tr|varak|guman=erê}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=?}}
# [[kelûpel]], [[tişt]], [[hûrûmûr]]
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|item}}, {{W+|en|goods}}, {{W+|en|wares}}, {{W+|en|products}}
{{werger-bin}}
== {{ziman|zza}} ==
=== Navdêr ===
{{navdêr|zza}}
# [[pel]]
== {{ziman|gl}} ==
=== Navdêr ===
{{navdêr|gl|z=m}}
# {{f|gl|anatomî}} [[çerm#ku|çerm]]
== {{ziman|oc}} ==
=== Navdêr ===
{{navdêr|oc|z=n}}
# {{f|oc|anatomî}} [[mû#ku|mû]], [[pûrt#ku|pûrt]], [[pirç#ku|pirç]]
== {{ziman|rm}} ==
=== Navdêr ===
{{navdêr|rm}}
# {{f|rm|anatomî}} [[çerm#ku|çerm]]
o83xivdn0sexmgx6b8qjmbcje10hgj6
6241664
6241663
2026-07-11T20:32:39Z
Wikihez
7344
/* Werger */
6241664
wikitext
text/x-wiki
{{binêre herwiha/pel}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA|pʰɛl}}
* {{ku-kîte}}
=== Navdêr 1 ===
{{ku-tewîn-nav|pel|nêr}}
[[Wêne:Leaf 1 web.jpg|thumb|pel (1)]]
{{navdêr|ku|z=n}}, {{p-ya req}}
# {{maneid|ku|riwek}} [[parçe|Parçe]]yên [[çeq]]ên [[dar]]an ve [[şên]] dibin. ([[pêşî]] ji [[bişkoj]]an [[pişkivîn|dipişkivin]], [[paşî]] [[kesk]] dibin û [[talî|taliyê]] [[beyîn|dibeyin]] anku [[zer]] dibin û [[werîn|diwerin]] anku [[weşîn|diweşin]])
#: {{hevmane|ku|belçim|belçîm|bilçik|belçûm|pelçim|pelçîm|pelçûm}}
# [[per]], [[kaxez]], [[weraqe]], [[belgename]]
==== Bi alfabeyên din ====
* {{ku-ar|پەل}}
==== Ji wêjeya klasîk ====
* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Ah-i bêgavê ji dil tên me ji pêta di ceger</br>Bes tu bêfeyde nesîhet ke me dil bûye '''pelek'''}}
==== Herwiha ====
{{kol3|ku|cure=Herwiha|sernav = [https://twitter.com/wikiferheng/status/1710338730089689440 Çavkanî]
| {{hw|ku|pelg||Sirûc|Bîraçik|Xelfetî}}
| {{hw|ku|pel||Mêrdîn|Sêwreg|Amed|Pasûr|Çewlîg|Bazîd}}
| {{hw|ku|pelçim||Botan}}
| {{hw|ku|belg||Dîgor|Agirî|Wan}}
| {{hw|ku|belçim||Dêrsim|Serhed}}
| {{hw|ku|pelç||Hewag}}
| {{hw|ku|per||Semsûr}}
}}
==== Bide ber ====
{{stûn|
* {{g|ku|pell}}
* {{g|ku|pal}}
* {{g|ku|pêl}}
* {{g|ku|pil}}
* {{g|ku|pîl}}
* {{g|ku|pol}}
* {{g|ku|pul}}
* {{g|ku|pûl}}
* {{g|ku|bel}}
}}
==== Jê ====
{{kol3|ku|cure=Jê
|pel girtin<q:lêker>
|pelgirtin<q:navdêr>
|pelçûn<q:navdêr>
}}
==== Etîmolojî ====
Hevreha şêxbizinî ''[[welg]]'', zazakî ''[[velg]]''
* {{ji|ine-pro|ku|-}}: *'''welə'''- ("hirî, pûrt") > *'''wolko'''- ("mû, hirî, pûrt; giya; daristan")
:*{{ji|ira-pro||-}}: *'''warka'''- ("belg, pel")
::{{ae}}: '''verke'''- ("belg, pel")
::{{xpr}}: '''wrgr''' ("belg, pel")
::{{pal}}: '''werg ''' ("belg, pel")
::{{sog}}: '''wrkr ''' ("belg, pel")
::{{fa}}: '''berg''' ("belg, pel")
::{{mzn}}: '''verek''' ("belg, pel")
::{{ku}}: '''belg > pelg > pel'''
::{{zza}}: '''[[velg]]''' ("belg, pel")
:{{sa}}: '''velke'''- ("[[per]], [[bask]]") ...
:{{la}}: '''vellus'''- ("hirî, pûrt")
:{{de}}: '''Wolle'''- ("hirî, pûrt")
:{{en}}: '''wool'''- ("hirî, pûrt")
;{{biçûk|Çavkanî:
* {{Horn|r=47}}
* {{Lubotsky|r=98}}
* {{Pokorny|r=1139}}
}}
==== Bi zaravayên din ====
* soranî/erdelanî: gella, pelk
* zazakî/kirmanckî: pel, pelçim, pure, velg,
* kelhûrî/feylî/şêxbizinî: welg, welneg, werg, belg, berg, pelg
* hewramî/şebekî: welg
==== Werger ====
{{werger-ser|parçeyên çeqên daran ve şên dibin|id=riwek}}
* {{Z|ab}}: {{W-|ab|абӷьы}}
* {{Z|ace}}: {{W-|ace|ôn}}
* {{Z|ady}}: {{W-|ady|тхьэпкӏэ}}
* {{Z|aa}}: {{W-|aa|dalaa}}
* {{Z|af}}: {{W+|af|blaar}}
* {{Z|akl}}: {{W-|akl|dahon}}
* {{Z|sq}}: {{W+|sq|gjethe|m-p}}
* {{Z|pdc}}: {{W-|pdc|Blatt|nt}}
* {{Z|de}}: {{W+|de|Blatt|nt}}, {{W+|de|Laubblatt|nt}}
*: {{Z|gsw}}: {{W-|gsw|Blatt|nt}}
*: {{Z|gmw-cfr}}: {{W-|gmw-cfr|Blatt|nt}}
* {{Z|ryn}}: {{W-|ryn|葉|tr=はー, hā}}
* {{Z|ams}}: {{W-|ams|葉|tr=はー, hā}}
* {{Z|am}}: {{W-|am|ቅጠል}}
* {{Z|an}}: {{W+|an|fuella|m}}
* {{Z|arc}}:
*: {{Z|syc}}: {{W-|syc|ܛܪܦܐ|n|tr=ṭarpā}}
* {{Z|agj}}: {{W-|agj|ቅጠል|tr=qəțäl}}
* {{Z|rup}}: {{W-|rup|frãndzã|m}}, {{W-|rup|frundzã|m}}
* {{Z|as}}: {{W-|as|পাত|nt}}
* {{Z|bno}}: {{W-|bno|rahon}}, {{W-|bno|dahon}}
* {{Z|ast}}: {{W+|ast|fueya|m}}
* {{Z|ask}}: {{W-|ask|pār}}
* {{Z|tay}}: {{W-|tay|abau}}
* {{Z|ay}}: {{W+|ay|laphi}}
* {{Z|ain}}: {{W-|ain|ハㇺ|tr=ham}}
* {{Z|az}}: {{W+|az|yarpaq}}
* {{Z|bdq}}: {{W-|bdq|hla}}
* {{Z|ban}}: {{W-|ban|don}}
* {{Z|eu}}: {{W+|eu|hosto}}, {{W+|eu|orri}}
* {{Z|ba}}: {{W-|ba|япраҡ}}
* {{Z|be}}: {{W-|be|ліст|n}}
* {{Z|bn}}: {{W+|bn|পাতা}}
* {{Z|bho}}: {{W-|bho|पान}}
* {{Z|bol}}: {{W-|bol|kumi rewe}}
* {{Z|br}}: {{W+|br|delienn|m}}
* {{Z|kxd}}: {{W-|kxd|daun}}
* {{Z|bug}}: {{W-|bug|daung}}
* {{Z|bg}}: {{W+|bg|лист|n}}, {{W+|bg|листо́|nt}}
* {{Z|my}}: {{W+|my|အရွက်}}
* {{Z|bua}}: {{W-|bua|набша}}, {{W-|bua|набшаһан}}, {{W-|bua|намаа}}
* {{Z|kac}}: {{W-|kac|lap}}
* {{Z|ccc}}: {{W-|ccc|chijpana}}
* {{Z|cjm}}: {{W-|cjm|ꨈꨶꨮꩉ}}, {{W-|cjm|ꨨꨤꨩ}}
* {{Z|cbk}}: {{W-|cbk|ohas}}
* {{Z|ce}}: {{W-|ce|гӏа}}
* {{Z|cs}}: {{W+|cs|list|n}}
* {{Z|chr}}: {{W-|chr|ᎤᎦᎶᎬ}}
* {{Z|ny}}: {{W-|ny|tsamba}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|葉|tr=jip6}}, {{W-|yue|葉子|tr=jip6 zi2}}
*: {{Z|dng}}: {{W-|dng|еезы}}, {{W-|dng|еер}}, {{W-|dng|езы}}
*: {{Z|hak}}: {{W-|hak|葉|tr=ya̍p}}
*: {{Z|cjy}}: {{W-|cjy|葉子|tr=ieh4 zeh}}
*: {{Z|cmn}}: {{W+|cmn|葉|tr=yè}}, {{W+|cmn|葉子|tr=yèzi}}
*: {{Z|cdo}}: {{W-|cdo|箬箬|tr=niŏh-niŏh}}
*: {{Z|nan}}: {{W+|nan|葉|tr=ia̍p}}, {{W+|nan|葉仔|tr=hio̍h-á}}
*: {{Z|wuu}}: {{W-|wuu|葉}}, {{W-|wuu|葉子}}
*: {{Z|hsn}}: {{W-|hsn|葉子|tr=ie6 zr}}
* {{Z|cv}}: {{W-|cv|ҫулҫӑ}}
* {{Z|dlm}}: {{W-|dlm|fualja|m}}
* {{Z|da}}: {{W+|da|blad|nt}}, {{W-|da|løv|nt}}
* {{Z|duu}}: {{W-|duu|vng'lvp}}
* {{Z|id}}: {{W+|id|daun}}
* {{Z|enq}}: {{W-|enq|yoko}}
* {{Z|ar}}: {{W-|ar|وَرَقَة|m}}
* {{Z|hy}}: {{W-|hy|տերեւ}}
* {{Z|myv}}: {{W-|myv|лопа}}
* {{Z|eo}}: {{W+|eo|folio}}
* {{Z|et}}: {{W+|et|leht}}
* {{Z|gez}}: {{W-|gez|ቈጽል}}
* {{Z|eve}}: {{W-|eve|эбдэнрэ}}
* {{Z|evn}}: {{W-|evn|авданна}}
* {{Z|ee}}: {{W-|ee|aŋgba}}
* {{Z|fa}}: {{W+|fa|برگ|tr=barg}}
* {{Z|fo}}: {{W-|fo|blað|nt}}
* {{Z|fj}}: {{W+|fj|drau}}
* {{Z|fi}}: {{W+|fi|lehti}}
* {{Z|fon}}: {{W-|fon|ama}}
* {{Z|frp}}: {{W-|frp|fôlye|m}}
* {{Z|fro}}: {{W-|fro|fueille|m}}
* {{Z|fr}}: {{W+|fr|feuille|m}}
* {{Z|fur}}: {{W-|fur|fuee|m}}
* {{Z|stq}}: {{W-|stq|Blääd|nt}}
* {{Z|fy}}: {{W-|fy|blêd}}
* {{Z|ff}}:
*: Latînî: {{W-|ff|haako}}, {{W-|ff|kaakol}}
*: Adlamî: {{W-|ff|𞤸𞤢𞥄𞤳𞤮}}, {{W-|ff|𞤳𞤢𞥄𞤳𞤮𞤤}}
* {{Z|fuy}}: {{W-|fuy|hutu}}
* {{Z|gd}}: {{W-|gd|duille|m}}, {{W-|gd|duilleag|m}}
* {{Z|gl}}: {{W+|gl|folla|m}}
* {{Z|glk}}: {{W-|glk|ولگ}}
* {{Z|gu}}: {{W-|gu|પાન|m}}, {{W-|gu|પર્ણ|nt}}, {{W-|gu|પાંદડું|nt}}, {{W-|gu|દલ}}
* {{Z|ka}}: {{W+|ka|ფოთოლი}}
* {{Z|gn}}: {{W+|gn|togue}}
* {{Z|gwi}}: {{W-|gwi|chʼatʼan}}
* {{Z|ht}}: {{W-|ht|fèy}}
* {{Z|haw}}: {{W-|haw|lau}}
* {{Z|ha}}: {{W+|ha|ganye}}, {{W-|ha|warƙa}}
* {{Z|mba}}: {{W-|mba|dahon}}
* {{Z|hi}}: {{W+|hi|पत्ता|n}}, {{W+|hi|पत्ती|m}}
* {{Z|ho}}: {{W-|ho|raurau}}
* {{Z|hil}}: {{W-|hil|dahon}}
* {{Z|meu}}: {{W-|meu|rau}}
* {{Z|mww}}: {{W-|mww|nplooj}}
* {{Z|nl}}: {{W+|nl|blad|nt}}
* {{Z|hop}}: {{W-|hop|nàapi}}
* {{Z|he}}: {{W+|he|עָלֶה|n|tr=alé}}
* {{Z|io}}: {{W+|io|folio}}
* {{Z|ig}}: {{W-|ig|akwụkwọ}}
* {{Z|inz}}: {{W-|inz|qap}}
* {{Z|ang}}: {{W+|ang|lēaf|nt}}
* {{Z|en}}: {{W+|en|leaf}}
* {{Z|izh}}: {{W-|izh|lehti}}
* {{Z|ia}}: {{W-|ia|folio}}
* {{Z|iu}}: {{W-|iu|ᐊᑭᕈᐊᕈᖅ}}
* {{Z|ill}}: {{W-|ill|raun}}
* {{Z|ga}}: {{W+|ga|duilleog|m}}, {{W+|ga|bileog|m}}
* {{Z|it}}: {{W+|it|foglia|m}}
* {{Z|ium}}: {{W-|ium|normh}}
* {{Z|is}}: {{W+|is|lauf|nt}}, {{W+|is|laufblað|nt}}
* {{Z|ja}}: {{W+|ja|葉|tr=は, ha}}, {{W+|ja|葉っぱ|tr=はっぱ, happa}}, {{W+|ja|木の葉|tr=このは, konoha}}
* {{Z|jra}}: {{W-|jra|hla}}
* {{Z|kaw}}: {{W-|kaw|ron}}
* {{Z|jv}}: {{W+|jv|godhong}}, {{W-|jv|ron}}
* {{Z|kl}}: {{W-|kl|pilu}}
* {{Z|bsh}}: {{W-|bsh|por}}
* {{Z|kn}}: {{W+|kn|ಎಲೆ}}
* {{Z|pam}}: {{W-|pam|bulung}}
* {{Z|krl}}: {{W-|krl|lehti}}
* {{Z|csb}}: {{W-|csb|lëst}}
* {{Z|ca}}: {{W+|ca|fulla|m}}
* {{Z|qu}}: {{W-|qu|raphi}}, {{W-|qu|llaqhi}}
* {{Z|kha}}: {{W-|kha|sla}}
* {{Z|kzg}}: {{W-|kzg|葉|tr=ぱー, pā}}
* {{Z|ky}}: {{W+|ky|жалбырак}}
* {{Z|ki}}: {{W-|ki|ithangũ|c5}}
* {{Z|si}}: {{W-|si|කොළේ}}, {{W-|si|කොළය}}
* {{Z|kyi}}: {{W-|kyi|dun}}
* {{Z|koi}}: {{W-|koi|кор}}
* {{Z|swb}}: {{W-|swb|wani|c11|c6}}
* {{Z|kok}}: {{W-|kok|पाल्लो|tr=pāllo}}
* {{Z|ko}}: {{W+|ko|잎}}
* {{Z|co}}: {{W+|co|foglia|m}}
* {{Z|cr}}:
*: {{Z|crk}}: {{W-|crk|nīpiy}}
* {{Z|xug}}: {{W-|xug|葉|tr=ぱー, phā}}
* {{Z|lad}}: {{W-|lad|foja|m}}, {{W-|lad|yaprak|n}}
* {{Z|lkt}}: {{W-|lkt|wahpe}}, {{W-|lkt|ape}}
* {{Z|ltg}}: {{W-|ltg|lopa|m}}
* {{Z|la}}: {{W+|la|folium|nt}}, {{W-|la|frons|m}}
* {{Z|lv}}: {{W+|lv|lapa|m}}
* {{Z|lo}}: {{W-|lo|ໃບ}}, {{W+|lo|ໃບໄມ້}}
* {{Z|ln}}: {{W-|ln|nkásá|c9|c10}}, {{W-|ln|lokásá|c11|c10}}
* {{Z|lij}}: {{W-|lij|féuggia|m}}
* {{Z|li}}: {{W+|li|louf|nt}}
* {{Z|lt}}: {{W+|lt|lapas|n}}
* {{Z|lmo}}: {{W-|lmo|foeuja|m}}, {{W-|lmo|fòia|m}}
* {{Z|lg}}: {{W-|lg|ekikoola}}
* {{Z|luy}}: {{W-|luy|lisafu}}
* {{Z|lb}}: {{W-|lb|Blat|nt}}
* {{Z|mhn}}: {{W-|mhn|lap|nt}}
* {{Z|mdh}}: {{W-|mdh|laun}}
* {{Z|mk}}: {{W-|mk|лист|n}}
* {{Z|mg}}: {{W+|mg|ravina}}, {{W+|mg|ravina}}
* {{Z|ml}}: {{W+|ml|ഇല}}
* {{Z|ms}}: {{W+|ms|daun}}
* {{Z|mt}}: {{W-|mt|werqa|m}}
* {{Z|mnc}}: {{W-|mnc|ᠠᠪᡩᠠᡥᠠ}}
* {{Z|gv}}: {{W-|gv|duillag|m}}
* {{Z|mns-nor}}: {{W-|mns-nor|лӯпта}}
* {{Z|mi}}: {{W+|mi|rau}}, {{W-|mi|tawhera}}
* {{Z|mrw}}: {{W-|mrw|ra'on}}
* {{Z|mr}}: {{W-|mr|पर्ण|nt}}, {{W+|mr|पत्र|nt}}, {{W+|mr|दल|nt}}
* Marî:
*: {{Z|mhr}}: {{W-|mhr|лышташ}}
*: {{Z|mrj}}: {{W-|mrj|ӹлӹштӓш}}
* {{Z|gun}}: {{W-|gun|ogue}}
* {{Z|hu}}: {{W+|hu|levél}}, {{W+|hu|falevél}}
* {{Z|mel}}: {{W-|mel|daun}}
* {{Z|egy}}: {{W-egy|gꜣbt|h=g-A-b-t-Hn:Z2ss}}
* {{Z|mvi}}: {{W-|mvi|葉|tr=ぱー, pā}}
* {{Z|lus}}: {{W-|lus|hnah}}
* {{Z|min}}: {{W-|min|daun}}
* {{Z|mwl}}: {{W-|mwl|fuolha|m}}
* {{Z|xpq}}: {{W-|xpq|wunipaq}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|навч}}
*: Mongolî: {{W-|mn|ᠨᠠᠪᠴᠢ}}
* {{Z|mnw}}: {{W-|mnw|သၠ|tr=hlaˀ}}
* {{Z|mtq}}: {{W-|mtq|lả}}
* {{Z|nah}}: {{W+|nah|izhuatl}}
* {{Z|gld}}: {{W-|gld|хабдата}}
* {{Z|nv}}: {{W-|nv|atʼąąʼ}}
* {{Z|nds}}:
*: {{Z|nds-de}}: {{W-|nds-de|Blatt|nt}}
* {{Z|ne}}: {{W+|ne|पात}}
* {{Z|ncb}}: {{W-|ncb|dai}}
* {{Z|nrf}}: {{W-|nrf|fielle|m}}, {{W-|nrf|fieille|m}}, {{W-|nrf|fuule|m}}, {{W-|nrf|fiëly|m}}
* {{Z|no}}:
*: {{Z|nb}}: {{W+|nb|blad|nt}}, {{W+|nb|løv|nt}}
*: {{Z|nn}}: {{W-|nn|blad|nt}}, {{W-|nn|lauv|nt}}
* {{Z|oj}}: {{W-|oj|aniibiishibag}}, {{W-|oj|aniibiishibagoon|p}}, {{W-|oj|aniibiish}}, {{W-|oj|aniibiishan|p}}, {{W-|oj|ᐊᓂᐱᐦᔑᐸᐟ|tr=aniibiishibag}}, {{W-|oj|ᐊᓂᐱᐦᔑᐸᑯᐣ|p|tr=aniibiishibagoon}}, {{W-|oj|ᐊᓂᐱᐦᐡ|tr=aniibiish}}, {{W-|oj|ᐊᓂᐱᐦᔕᐣ|p|tr=aniibiishan}}
* {{Z|okn}}: {{W-|okn|葉|tr=はー, fā}}
* {{Z|ryu}}: {{W-|ryu|葉|tr=ふぁー, fā}}
* {{Z|oc}}: {{W+|oc|fuèlha|m}}
* {{Z|one}}: {{W-|one|onláhte̲’}}
* {{Z|or}}: {{W+|or|ପତ୍ର}}
* {{Z|osa}}: {{W-|osa|žąąpé}}
* {{Z|os}}: {{W-|os|сыф}}
* {{Z|ota}}: {{W-|ota|یپراق|tr=yaprak}}
* {{Z|ug}}: {{W-|ug|يوپۇرماق}}, {{W-|ug|ياپراق}}
* {{Z|uz}}: {{W+|uz|yaproq}}, {{W+|uz|barg}}
* {{Z|pac}}: {{W-|pac|ula}}, {{W-|pac|ila}}
* {{Z|pau}}: {{W-|pau|llel}}
* Pali:
*: {{Z|pi}}: {{W-|pi|ပဏ္ဏ|nt}}
*: {{Z|pi}}: {{W-|pi|पण्ण|nt}}
*: {{Z|pi}}: {{W-|pi|បណ្ណ|nt}}
*: Latînî: {{W-|pi|paṇṇa|nt}}
*: {{Z|pi}}: {{W-|pi|පණ්ණ|nt}}
*: {{Z|pi}}: {{W-|pi|ปณฺณ|nt}}
* {{Z|pap}}: {{W-|pap|foya}}
* {{Z|bxd}}: {{W-|bxd|a³¹faʔ⁵⁵}}, {{W-|bxd|sak⁵⁵ faʔ⁵⁵}}
* {{Z|ps}}: {{W+|ps|پاڼه|m|tr=pâṇa}}
* {{Z|pms}}: {{W-|pms|feuja|m}}
* {{Z|ppl}}: {{W-|ppl|iswat}}, {{W-|ppl|izhuat}}
* {{Z|pdt}}: {{W-|pdt|Blaut|nt}}
* {{Z|pl}}: {{W+|pl|liść|n}}
* {{Z|pt}}: {{W+|pt|folha|m}}
* {{Z|prn}}: {{W-|prn|pārag}}
* {{Z|pa}}: {{W-|pa|ਪੱਤਾ|n}}
* {{Z|kk}}: {{W-|kk|жапырақ}}
* {{Z|rap}}: {{W-|rap|rua}}
* {{Z|rhg}}: {{W-|rhg|fata}}
* {{Z|rgn}}: {{W-|rgn|fója|m}}
* {{Z|rm}}: {{W-|rm|fegl}}
* {{Z|rom}}: {{W-|rom|patrin|m}}
* {{Z|ro}}: {{W+|ro|frunză|m}}
* {{Z|ru}}: {{W+|ru|лист|n}}, plural for this sense: {{W+|ru|ли́стья|n-p}}
* {{Z|ksw}}: {{W-|ksw|သ့ၣ်လၣ်}}
* {{Z|ssy}}: {{W-|ssy|dharhaa}}
* {{Z|se}}: {{W-|se|lasta}}
* {{Z|sm}}: {{W-|sm|lau}}
* {{Z|sa}}: {{W+|sa|पर्ण|tr=parṇá|nt}}, {{W+|sa|पत्र|nt}}
* {{Z|sc}}: {{W-|sc|fògia|m}}
* {{Z|ceb}}: {{W-|ceb|dahon}}
* {{Z|sea}}: {{W-|sea|sela}}
* {{Z|scn}}: {{W+|scn|fogghia|m}}
* {{Z|sd}}: {{W-|sd|پن|n|tr=panu|cuda=پَنُ}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|лист|n}}, {{W-|sh|лиска|m}}
*: Latînî: {{W+|sh|list|n}}, {{W+|sh|liska|m}}
* {{Z|cu}}:
*: Kirîlî: {{W-|cu|листъ|n}}
*: Glagolîtîk: {{W-|cu|ⰾⰹⱄⱅⱏ|n}}
* {{Z|orv}}: {{W-|orv|листъ|n}}
* {{Z|sk}}: {{W+|sk|list|n}}
* {{Z|sl}}: {{W+|sl|list|n}}
* {{Z|zlw-slv}}: {{W-|zlw-slv|lȧ̃st|n}}
* {{Z|so}}: {{W+|so|caleen|m}}
* Sorbî:
*: {{Z|dsb}}: {{W-|dsb|list|n}}
*: {{Z|hsb}}: {{W-|hsb|list|n}}
* {{Z|es}}: {{W+|es|hoja|m}}
* {{Z|su}}: {{W+|su|daun}}
* {{Z|sw}}: {{W+|sw|jani|c5|c6}}, {{W+|sw|msahafu|c3|c4}}
* {{Z|sv}}: {{W+|sv|blad|nt}}, {{W+|sv|löv|nt}}
* {{Z|shn}}: {{W-|shn|မႂ်}}, {{W-|shn|ဝႂ်}}
* {{Z|zdj}}: {{W-|zdj|wani|c11|c10}}
* {{Z|sn}}: {{W-|sn|shizha}}
* {{Z|tg}}: {{W+|tg|барг}}
* {{Z|tl}}: {{W+|tl|dahon}}
* {{Z|tly}}: {{W-|tly|لیو}}
* {{Z|ta}}: {{W+|ta|இலை}}
* {{Z|twf}}: {{W-|twf|ə̂na}}
* {{Z|roa-tar}}: {{W-|roa-tar|fogghie|m}}
* {{Z|rif}}: {{W-|rif|afar|n}}, {{W-|rif|tifrešt|m}}
* {{Z|tsg}}: {{W-|tsg|dahun}}
* {{Z|th}}: {{W+|th|ใบ}}, {{W+|th|ใบไม้}}
* {{Z|te}}: {{W+|te|ఆకు}}
* {{Z|tzm}}: {{W-|tzm|ⵉⴼⴻⵔ|n}}
* {{Z|tea}}: {{W-|tea|sela}}
* {{Z|tt}}: {{W+|tt|яфрак}}
* {{Z|tet}}: {{W-|tet|roo}}
* {{Z|tr}}: {{W+|tr|yaprak}}
* {{Z|tk}}: {{W-|tk|ýaprak}}
* {{Z|bo}}: {{W-|bo|ལོ་མ།}}
* {{Z|tli}}: {{W-|tli|kayaaní}}
* {{Z|tpi}}: {{W-|tpi|lip}}
* {{Z|tkn}}: {{W-|tkn|葉|tr=はー, hā}}
* {{Z|xto}}: {{W-|xto|pält}}
* {{Z|txb}}: {{W-|txb|pilta}}
* {{Z|trm}}: {{W-|trm|påṭ}}
* {{Z|tcy}}: {{W-|tcy|ಅಡಿಪಿರೆ}}
* {{Z|tvl}}: {{W-|tvl|lau}}
* {{Z|tpw}}: {{W-|tpw|oba}}
* {{Z|udi}}: {{W-|udi|хазал}}
* {{Z|udm}}: {{W-|udm|куар}}
* {{Z|ur}}: {{W-|ur|پتی|m|tr=patti}}
* {{Z|uk}}: {{W+|uk|лист|n}}
* {{Z|vec}}: {{W+|vec|foja|m}}, {{W-|vec|fogia|m}}
* {{Z|vep}}: {{W-|vep|leht}}
* {{Z|vi}}: {{W+|vi|lá}}
* {{Z|vo}}: {{W+|vo|bled}}
* {{Z|vor}}: {{W-|vor|leht'}}
* {{Z|vot}}: {{W-|vot|lehti}}
* {{Z|wbk}}: {{W-|wbk|poṭ}}
* {{Z|wa}}: {{W+|wa|foye|m}}
* {{Z|war}}: {{W-|war|dáhon}}
* {{Z|cy}}: {{W+|cy|deilen|m}}
* {{Z|wym}}: {{W-|wym|błot|nt}}
* {{Z|wo}}: {{W+|wo|xob}}
* {{Z|km}}: {{W+|km|ស្លឹក}}, {{W-|km|ស្លឹកឈើ}}
* {{Z|xh}}: {{W-|xh|igqabi|c5|c6}}
* {{Z|rys}}: {{W-|rys|葉|tr=ぱー, pā}}
* {{Z|sah}}: {{W-|sah|сэбирдэх}}
* {{Z|yag}}: {{W-|yag|Suka}}
* {{Z|yi}}: {{W-|yi|בלאַט|n|m}}
* {{Z|yoi}}: {{W-|yoi|葉|tr=はー, hā}}
* {{Z|yox}}: {{W-|yox|葉|tr=ぱー, pā}}
* {{Z|yo}}: {{W-|yo|ewé}}
* {{Z|el}}: {{W+|el|φύλλο|nt}}
*: Kevn: {{W-|grc|φύλλον|nt}}, {{W-|grc|πέταλον|nt}}
* {{Z|zea}}: {{W-|zea|blad|nt}}
* {{Z|za}}: {{W-|za|mbaw}}
* {{Z|zu}}: {{W+|zu|ikhasi|c5|c6}}, {{W+|zu|iqabi|c5|c6}}
{{werger-bin}}
:{{werger çavkanî|en|leaf|beş=Ev qismê Wergerê|oldid=76702326}}
{{werger-ser|per, kaxez, weraqe, belgename}}
* {{Z|de}}: {{W+|de|Laub}} {{n}}, {{W+|de|Seite}} {{m}}, {{W+|de|Wedel|guman=erê}} {{n}}
* {{Z|fa}}: {{W+|fa|برگ}}, {{W+|fa|سند}}, {{W+|fa|صفحه}}, {{W+|fa|برگه|guman=erê}}, {{W-|fa|شراره آتش|guman=erê}}, {{W+|fa|کاغذ|guman=erê}}, {{W+|fa|مدرک|guman=erê}}
* {{Z|en}}: {{W+|en|covey}}, {{W+|en|foliage}}, {{W+|en|frond}}, {{W+|en|gleed}}, {{W+|en|platoon}}, {{W+|en|file}}, {{W+|en|phyllo-}}
* {{Z|tr}}: {{W+|tr|belge}}, {{W+|tr|çalkantı}}, {{W+|tr|çapak}}, {{W+|tr|lahza|guman=erê}}
{{werger-bin}}
=== Navdêr 2 ===
[[Wêne:Embers 01.JPG|thumb|250px|pel (2)]]
{{navdêr|ku|z=n}}
# [[parçe|Parçe]]yên [[agir]]î yên ji [[pirt]]ên [[dar]]î yan [[kumir]]ê yên ku agirî girtine û dişewitin lê hê nebûne [[xwelî]].
#: {{hevmane|ku|pêt}}
==== Bi alfabeyên din ====
* {{ku-ar|پهل}}
==== Herwiha ====
* {{g|ku|pêlox}}
* {{g|ku|pêreng}}
* {{g|ku|piring}}
* {{g|ku|piloxt}}
==== Etîmolojî ====
Herwiha [[piring]], [[pêreng]], ji {{ji|ine-pro|ku|*péh₂ur|t=[[agir]]}}.
Hevreha çekî [[pýř]] (pel), {{hv|grc|πῦρ}} (pûr: agir > kurdî [[pîroman]]), [[toxarî]] A ''por'' (agir), toxarî B ''puwar'' (agir), hîtîtî ''paḫḫur'' ([[agir]]), danmarkî / norwecî / {{hv|sv|fyr}} (agir), îngilîzî [[fire]] (agir), {{hv|hy|հուր}} (hur: agir)...
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Glut}} {{m}}
* {{Z|zh}}:
*: [[mandarînî]]: {{W+|cmn|餘燼|sc=Hani|xs=Mandarin}}, {{W+|cmn|余烬|tr=yújìn|sc=Hani|xs=Mandarin}}
* {{Z|ar}}: {{W-|ar|جمرة|tr=cemre}}
* {{Z|hy}}: {{W-|hy|մարմրող ածուխ|tr=marmroġ açux}}
* {{Z|eo}}: {{W-|eo|braĝo|xs=Esperanto}}, {{W-|eo|ardaĵo|xs=Esperanto}}
* {{Z|fa}}: {{W+|fa|شعله|sc=fa-Arab}}
* {{Z|fi}}: {{W+|fi|kekäle}}
* {{Z|fr}}: {{W+|fr|braise}} {{m}}
* {{Z|ka}}: {{W-|ka|მღვივარი ნახშირი|tr=mġvivari naxširi}}, {{W-|ka|ცხელი ნაცარი|tr=tsxeli natsari}}
* {{Z|nl}}: {{W+|nl|sintel}}
* {{Z|io}}: {{W+|io|brezo}}
* {{Z|en}}: {{W+|en|embers}}, {{W+|en|ember}}, {{W+|en|bracteole|guman=erê}}, {{W+|en|bractlet|guman=erê}}, {{W+|en|carbuncle|guman=erê}}, {{W+|en|fire-brand|guman=erê}}, {{W+|en|leafage|guman=erê}}, {{W-|en|live coal|guman=erê}}, {{W+|en|phyllome|guman=erê}}, {{W+|en|cigarette paper|guman=erê}}
* {{Z|it}}: {{W+|it|brace}} {{m}}
* {{Z|ca}}: {{W+|ca|brasa}} {{m}}
* {{Z|la}}: {{W+|la|favilla}} {{m}}
* {{Z|hu}}: {{W+|hu|zsarátnok}}; [[izzó fa]]([[darab]])/[[széndarab]], {{W+|hu|parázs}}
* {{Z|ru}}: {{W+|ru|уголёк|tr=ugoljók}} {{n}}, {{W-|ru|tr=gorjáčaja zolá|горячая зола}} {{m}}
* {{Z|sh}}: {{W+|sh|žar}} {{n}}, {{W+|sh|žeravica}} {{m}}
* {{Z|es}}: {{W+|es|brasa}} {{m}}, {{W+|es|ascua}} {{m}}
* {{Z|th}}: {{W-|th|แสงไฟในเศษฟืน|tr=săeng fai nai sèt feun}}, {{W-|th|ถ่านที่ยังคุอยู่|tr=tàan têe yang kóo yòo}}, {{W-|th|เถ้าที่ยังคุกกรุ่นอยู่|tr=tâo têe yang kóok gròon yòo}}
* {{Z|tr}}: {{W+|tr|kor}}, {{W+|tr|köz}}, {{W+|tr|levha|guman=erê}}, {{W+|tr|manga|guman=erê}}, {{W+|tr|sarma|guman=erê}}, {{W+|tr|takım|guman=erê}}, {{W+|tr|talaş|guman=erê}}, {{W+|tr|talaz|guman=erê}}, {{W+|tr|tim|guman=erê}}, {{W+|tr|titrek kavak|guman=erê}}, {{W+|tr|varak|guman=erê}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=?}}
# [[kelûpel]], [[tişt]], [[hûrûmûr]]
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|item}}, {{W+|en|goods}}, {{W+|en|wares}}, {{W+|en|products}}
{{werger-bin}}
== {{ziman|zza}} ==
=== Navdêr ===
{{navdêr|zza}}
# [[pel]]
== {{ziman|gl}} ==
=== Navdêr ===
{{navdêr|gl|z=m}}
# {{f|gl|anatomî}} [[çerm#ku|çerm]]
== {{ziman|oc}} ==
=== Navdêr ===
{{navdêr|oc|z=n}}
# {{f|oc|anatomî}} [[mû#ku|mû]], [[pûrt#ku|pûrt]], [[pirç#ku|pirç]]
== {{ziman|rm}} ==
=== Navdêr ===
{{navdêr|rm}}
# {{f|rm|anatomî}} [[çerm#ku|çerm]]
ptu7nb659ppcc5ezu1sdhveo1op59te
ava
0
3656
6241668
6101806
2026-07-11T20:37:21Z
Wikihez
7344
6241668
wikitext
text/x-wiki
{{bnr-h|Ava}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{beş|Rengdêr}} {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-ava.wav|Deng|Wan}}
* {{beş|Formeke navdêrê}} {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-ava-2.wav|Deng|Wan}}
* {{ku-kîte}}
=== Rengdêr ===
{{ku-tewîn-rd|ava}}
{{rengdêr|ku}}
# Ne [[kavil]], ne [[xirabe]], ne [[xirabkirî]], ne [[xopan]], ne [[wêran]], ne [[ruxandî]], ne [[hilweşandî]]
#: {{hevmaneyên peyvê|ku|çêkirî|dirist|birêk|birêkûpêk|lidar|çalak|liserxwe}}
#: {{dijmane|ku|kavil|wêran|xirabe|xopan}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Spêde kifş-i bû dîsa</br>Merîxa nehsê '''ava''' bû</br>Xwiya bû roj di şerqê da}}
==== Bi alfabeyên din ====
* {{ku-ar|ئاڤا}}
==== Herwiha ====
* {{g|ku|awa}} (2)
==== Jê ====
{{kol3|ku|cure=Jê
|-ava
|avahî
|avakar
|avakarî
|avaker
|avakerî
|avanî
|avatî
|avayî
|ava kirin<q:lêker>
|ava bûn<q:lêker>
|avabûn<q:navdêr>
|avakirin<q:navdêr>
|avadan
|avabûyî<q:rengdêr>
|avakirî<q:rengdêr>
|avaçûyî
}}
==== Etîmolojî ====
Ji {{mîr|ira-pro|ku|*āpāta-}} ji {{ji|ine-pro|ku|*peh₂-|w=[[parastin]]}}, têkilî {{hv|fa|آباد|tr=abad}} û {{hv|ckb|ئاوهدان}} / [[awedan]], {{hv|zza|awan}}. Belkî hevreha {{hv|sa|आवास}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|built}}
* {{Z|tr}}: {{W+|tr|bayındır}}, {{W+|tr|mamur}}, {{W+|tr|şen}}, {{W+|tr|abat}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|av|mê|îzafe|binavkirî}}
{{navdêr|ku|form=erê}}
# {{formeke peyvê|ku|av||îzafe|yekjimar|binavkirî}}
ajo78av5vtpzq8fa6v87n0hrhphznwg
lingwistîk
0
5080
6241712
5890695
2026-07-11T23:57:19Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241712
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku|z=-}}
# {{guharto|ku|lenguîstîk}}
#* {{bêmînak|ku}}
0643cauoih4dra2krs0trqw7dy12obo
kursî
0
6008
6241720
6129691
2026-07-12T00:26:58Z
Wikihez
7344
/* Navdêr */
6241720
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|kursî|mê}}
[[Wêne:Chair.png|thumb|kursiyek]]
{{navdêr|ku|z=m}}, {{k-ya nerm}}, {{r-ya nerm}}
# {{f|ku|mobîlya}} Alavên bi[[pişt]] û bi[[pêpik]] yên bi [[giştî]] bo [[rûniştin]]a kesekî.
#: {{mk|ku|Rûne ser '''kursiyê'''.}}
#: {{mk|ku|Li ser '''kursiyê''' rûniştim.}}
#: {{mk|ku|Ji ser '''kursiyê''' rabû.}}
#: {{mk|ku|Hemû '''kursî''' girtî bûn.|Li ser her yekê kesek hebû û ti yên vala tine bûn.|rêz=1}}
# [[diran|Diran]]ên [[paşîn]].
#* {{bêmînak|ku}}
# [[meqam|Meqam]], [[cih]].
#* {{bêmînak|ku}}
# [[meqam|Meqam]]ê [[paşa]]yan/[[desthilatdar]]an.
#: {{hevmane|ku|text}}
#: {{mk|ku|text û '''kursî'''}}
# [[meqam|Meqam]]ê [[Xwedê]].
#: {{hevmane|ku|erş}}
#: {{mk|ku|Ayeta '''Kursî'''|[[ayet]]a 2:255 a [[Qur'an]]ê ye û behsa bê[[hevta]]yiya [[Xwedê]] dike}}
#* {{jêder|ku|jêgirtin="Nîveka dî çêkirin ji çarî çîz</br>'Erş û '''kursî''' û qelem lewhe temîz</br>Hate emrê Padîşahê [[Layezal]]"'' |Mela Hisênê Bateyî: ''Mewlûd''}}
# Îdareya di nav [[unîversîte]]yan de ku li ser meseleyeke diyarkirî lêkolîn û dersan dide.
#: {{nm|ku|'''Kursiya''' zimanê kurdî di sala 1945an de ji aliyê Roger Lescot (1914-1975) ve hate avakirin.}}
==== Bi alfabeyên din ====
* {{ku-ar|کورسی}}
* {{ku-kr|курси}}
==== Herwiha ====
* {{g|ku|kursîk}}
==== Hevmane ====
* {{g|ku|sendelî}}
* {{g|ku|sendelye}}
* {{g|ku|rûniştek}}
==== Binêre herwiha ====
{{kol3|ku
|balguh
|balîf
|doşek
|doşk
|lihêf
|mobîlya
|nivîn
|palpişt
|qaîdok
|qenepe
|rûniştek
|sofa
|text
}}
==== Jê ====
* {{g|ku|rûniştin}} ser kursiyê
* li ser kursiyê [[rûniştin]]
* ji ser kursiyê [[rabûn]]
* {{g|ku|kursîk}}
==== Etîmolojî ====
Hevreha soranî {{g|ckb|کورسی}}, zazakî {{q|zza|kursî}}, {{hv|fa|کورسی|tr=berê "kursî", niha "korsî"}}, tirkî {{q|tr|kürsü}} (bi tirkiya osmanî {{g|ota|كرسى|ts=kursî}}), erebî {{g|ar|كرسي}} (bi erebiya standard "kursiyy", bi erebiya devkî "kursî, kirsî"), siryanî {{g|syc|ܟܘܪܣܝܐ|tr=kursiya}}, [[aramî]] {{g|arc|כרסא|tr=kursa}} û {{g|arc|כסא|tr=kusa}}, îbranî {{ge|he|כיסא|tr=kissê}}, ugarîtî [[𐎋𐎒𐎜]] (kisủ), akadî [[𒄖𒍝]] / [[𒄑𒄖𒍝]] (kussû, kursû)... hemû ji {{ji|sux|ku|𒄖𒍝|tr=gu.za}}.
Peyv ji Rojhilata Navîn belav bûye Başûrê Asyayê jî: ûrdûyî {{g|ur|کرسی|tr=kursī}}, peştûyî {{g|ps|کورسۍ|tr=kursiy}}, hindî [[कुरसी]] (kursī), punjabî [[ਕੁਰਸੀ]] (kursī)...
;{{biçûk|Çavkanî:
* {{kitêb|sernavê orjînalThe Pennsylvania Sumerian Dictionary|sernav=Ferhenga sûmerî ya Pennsylvaniayê|url=http://psd.museum.upenn.edu/nepsd-frame.html}}
* {{kitêb|url=http://www.assyrianlanguages.org/akkadian/dosearch.php?searchkey=16&language=id|sernav=Rêkxistina Aşûrîdostan ya Fransayê: Ferhenga akadî|sernavê orjînal='Association Assyrophile de France: Dictionnaire akkadien}}
}}
==== Werger ====
{{werger-ser}}
* {{Z|af}}: {{W-|af|stoel}}
* {{Z|sq}}: {{W-|sq|karrike|m}}, {{W+|sq|karrige}}
* {{Z|de}}: {{W+|de|Stuhl|n}}
* {{Z|ast}}: {{W+|ast|siella}}
* {{Z|az}}: {{W+|az|stul}}
* {{Z|eu}}: {{W+|eu|aulki}}
* {{Z|bar}}: {{W--|bar|Sessl|n}}
* {{Z|be}}: {{W-|be|стул|tr=stul}}
* {{Z|br}}: {{W+|br|kador|m}}
* {{Z|bg}}: {{W+|bg|стол|tr=stol}}
* {{Z|cs}}: {{W+|cs|židle}}
* {{Z|zh}}: {{W+|zh|椅子|tr=yǐzi}}
* {{Z|da}}: {{W+|da|stol}}
* {{Z|id}}: {{W+|id|kursi}}
* {{Z|ary}}: {{W--|ary|كرسي}}, {{W--|ary|شلية}}
*: {{Z|arz}}: {{W|arz|كرسي|tr=kursî}} {{n}}
* {{Z|ar}}: {{W|ar|كرسي|tr=kursiyy}} {{n}}, {{W|ar|مقعد|tr=meq'ed}} {{n}}
* {{Z|hy}}: {{W+|hy|աթոռ|tr=atʿoṙ}}
* {{Z|eo}}: {{W+|eo|seĝo}}
* {{Z|et}}: {{W+|et|tool}}
* {{Z|ewo}}: {{W--|ewo|etoa}}
* {{Z|fa}}: {{W+|fa|صندلی|tr=sendelî}}, {{W|fa|کرسی|tr=korsî}}
* {{Z|fo}}: {{W-|fo|stólur}}
* {{Z|fi}}: {{W+|fi|tuoli}}, {{W|fi|istuin}}
* {{Z|frp}}: ''(savoyard)'' {{W--|frp|sala}}
* {{Z|fr}}: {{W|fr|chaise}}
* {{Z|fy}}: {{W-|fy|stoel}}, {{W-|fy|belech}}
* {{Z|gd}}: {{W-|gd|suidheachan}}, {{W-|gd|cathair}}
* {{Z|gl}}: {{W+|gl|cadeira|m}}
* {{Z|ka}}: {{W+|ka|სკამი|tr=sḳami}}
* {{Z|hi}}: {{W+|hi|कुरसी|tr=kursī}}
* {{Z|nl}}: {{W+|nl|stoel}}, {{W+|nl|zetel}}
* {{Z|he}}: {{W+|he|כיסא|tr=kisé}}
* {{Z|io}}: {{W+|io|stulo}}
* {{Z|ang}}: {{W-|ang|stol}}
* {{Z|en}}: {{W+|en|chair}}, {{W+|en|seat}}
* {{Z|ga}}: {{W+|ga|cathaoir}}
* {{Z|it}}: {{W+|it|assedio}}, {{W+|it|sedia}}, {{W+|it|seggiola}}
* {{Z|is}}: {{W+|is|stóll}}
* {{Z|ja}}: {{W+|ja|椅子|tr=isu}}, {{W+|ja|いす|tr=isu}}
* {{Z|ca}}: {{W+|ca|cadira}}
* {{Z|ki}}: {{W--|ki|giti}}
* {{Z|ko}}: {{W+|ko|의자|tr=uija}}
* {{Z|kw}}: {{W-|kw|cadar}}
* {{Z|co}}: {{W+|co|sedia}}, {{W-|co|carreca}}
* {{Z|mfe}}: {{W--|mfe|sez}}
* {{Z|la}}: {{W-|la|sella}}, {{W-|la|cathedra}}, {{W-|la|solium}}
* {{Z|lv}}: {{W+|lv|krēsls}}
* {{Z|lo}}: {{W+|lo|ຕັ່ງ}}
* {{Z|lt}}: {{W+|lt|kėdė}}
* {{Z|mk}}: {{W-|mk|стол|tr=stol}}, {{W-|mk|столица|tr=stolica}}
* {{Z|mg}}: {{W+|mg|seza}}
* {{Z|ms}}: {{W+|ms|kursi}}
* {{Z|mt}}: {{W+|mt|siġġu}}
* {{Z|gv}}: {{W-|gv|caair}}
* {{Z|yua}}: {{W--|yua|k’anche’}}
* {{Z|hu}}: {{W+|hu|szék}}
* {{Z|mn}}: {{W+|mn|сандал|tr=sandal}}
* {{Z|nrf}}: {{W--|nrf|caire}}
* {{Z|no}}: {{W+|no|stol|nt}}
* {{Z|oc}}: {{W+|oc|cadièra|m}}
* {{Z|uz}}: {{W+|uz|o`rindiq}}
* {{Z|uz}}: {{W|uz|o`rindiq}}
* {{Z|pap}}: {{W--|pap|stul}}
* {{Z|pl}}: {{W+|pl|krzesło}}
* {{Z|pt}}: {{W+|pt|cadeira|m}}, {{W+|pt|assento}}
* {{Z|kk}}: {{W+|kk|орындық|tr=orındıq}}, {{W-|kk|отырғыш|tr=otırğış}}
* {{Z|ro}}: {{W+|ro|scaun}}
* {{Z|ru}}: {{W+|ru|стул}}
* {{Z|se}}: {{W--|se|stuollu}}
* {{Z|srn}}: {{W--|srn|sturu}}
* {{Z|sh}}:
:* Latînî: {{W+|sh|stolac}}, {{W+|sh|stolica}}
:* Kirîlî: {{W-|sh|столац}}, {{W+|sh|столица}}
* {{Z|sk}}: {{W-|sk|stolička}}
* {{Z|sl}}: {{W+|sl|stol}}
* {{Z|dsb}}: {{W--|dsb|stoł}}
* {{Z|hsb}}: {{W-|hsb|stólc}}
* {{Z|es}}: {{W+|es|silla|m}}
* {{Z|sw}}: {{W+|sw|kiti}}
* {{Z|sv}}: {{W+|sv|stol}}
* {{Z|shy}}: {{W--|shy|amɣim}}
* {{Z|zdj}}: {{W--|zdj|hiri}}
* {{Z|tg}}: {{W-|tg|сандали|tr=sandali}}, {{W+|tg|курсӣ|tr=kursī}}
* {{Z|tl}}: {{W-|tl|sílya}}, {{W-|tl|úpuan}}
* {{Z|ta}}: {{W+|ta|நாற்காலி|tr=nāṟkāli}}
* {{Z|th}}: {{W+|th|เก้าอี้|tr=gâo-îi}}
* {{Z|tr}}: {{W+|tr|sandalye}}, {{W|tr|sandalye}}, {{W|tr|kürsü}}, {{W|tr|koltuk}}, {{W|tr|iskemle}}, {{W|tr|oturak}}, {{W|tr|tabure}}, {{W|tr|sekmen}}
* {{Z|tk}}: {{W-|tk|oturgyç}}
* {{Z|ur}}: {{W-|ur|کرسی|tr=kursī}}
* {{Z|ur}}: {{W|ur|کرسی|tr=kursī}} {{n}}
* {{Z|uk}}: {{W+|uk|стілець|tr=stilécʹ}}, {{W-|uk|крісло|tr=kríslo}}
* {{Z|vec}}: {{W|vec|carega}}
* {{Z|vi}}: {{W|vi|ghế}}
* {{Z|cy}}: {{W+|cy|cadair}}
* {{Z|cy}}: {{W|cy|cadair}}, {{W|cy|ystôl}}
* {{Z|km}}: {{W+|km|កៅអី|tr=kav ’əy}}
* {{Z|yi}}: {{W|yi|שטול}}
* {{Z|el}}: {{W+|el|καρέκλα|tr=karékla}}
* {{Z|el}}: {{W|el|καρέκλα}} {{n}} (karékla)
* {{Z|zu}}: {{W+|zu|isihlalo}}
{{werger-bin}}
== {{ziman|ckb}} ==
=== Navdêr ===
{{navdêr|ckb|sc=Latn}}
# {{ckb-Arab|کورسی}}
== {{ziman|zza}} ==
=== Navdêr ===
{{navdêr|zza}}
# [[kursî#Kurmancî|kursî]]
#* {{bêmînak|zza}}
13vzbzeoq0dyh5kds93ggr28xpqceji
6241721
6241720
2026-07-12T00:27:28Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241721
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|kursî|mê}}
[[Wêne:Chair.png|thumb|kursiyek]]
{{navdêr|ku|z=m}}, {{k-ya nerm}}, {{r-ya nerm}}
# {{f|ku|mobîlya}} Alavên bi[[pişt]] û bi[[pêpik]] yên bi [[giştî]] bo [[rûniştin]]a kesekî.
#: {{mk|ku|Rûne ser '''kursiyê'''.}}
#: {{mk|ku|Li ser '''kursiyê''' rûniştim.}}
#: {{mk|ku|Ji ser '''kursiyê''' rabû.}}
#: {{mk|ku|Hemû '''kursî''' girtî bûn.|Li ser her yekê kesek hebû û ti yên vala tine bûn.|rêz=1}}
# [[diran|Diran]]ên [[paşîn]].
#* {{bêmînak|ku}}
# [[meqam|Meqam]], [[cih]].
#* {{bêmînak|ku}}
# [[meqam|Meqam]]ê [[paşa]]yan/[[desthilatdar]]an.
#: {{hevmane|ku|text}}
#: {{mk|ku|text û '''kursî'''}}
# [[meqam|Meqam]]ê [[Xwedê]].
#: {{hevmane|ku|erş}}
#: {{mk|ku|Ayeta '''Kursî'''|[[ayet]]a 2:255 a [[Qur'an]]ê ye û behsa bê[[hevta]]yiya [[Xwedê]] dike}}
#* {{jêder|ku|jêgirtin="Nîveka dî çêkirin ji çarî çîz</br>'Erş û '''kursî''' û qelem lewhe temîz</br>Hate emrê Padîşahê [[Layezal]]"'' |Mela Hisênê Bateyî: ''Mewlûd''}}
# {{e|ku|tehsîl}} Îdareya di nav [[unîversîte]]yan de ku li ser meseleyeke diyarkirî lêkolîn û dersan dide.
#: {{nm|ku|'''Kursiya''' zimanê kurdî di sala 1945an de ji aliyê Roger Lescot (1914-1975) ve hate avakirin.}}
==== Bi alfabeyên din ====
* {{ku-ar|کورسی}}
* {{ku-kr|курси}}
==== Herwiha ====
* {{g|ku|kursîk}}
==== Hevmane ====
* {{g|ku|sendelî}}
* {{g|ku|sendelye}}
* {{g|ku|rûniştek}}
==== Binêre herwiha ====
{{kol3|ku
|balguh
|balîf
|doşek
|doşk
|lihêf
|mobîlya
|nivîn
|palpişt
|qaîdok
|qenepe
|rûniştek
|sofa
|text
}}
==== Jê ====
* {{g|ku|rûniştin}} ser kursiyê
* li ser kursiyê [[rûniştin]]
* ji ser kursiyê [[rabûn]]
* {{g|ku|kursîk}}
==== Etîmolojî ====
Hevreha soranî {{g|ckb|کورسی}}, zazakî {{q|zza|kursî}}, {{hv|fa|کورسی|tr=berê "kursî", niha "korsî"}}, tirkî {{q|tr|kürsü}} (bi tirkiya osmanî {{g|ota|كرسى|ts=kursî}}), erebî {{g|ar|كرسي}} (bi erebiya standard "kursiyy", bi erebiya devkî "kursî, kirsî"), siryanî {{g|syc|ܟܘܪܣܝܐ|tr=kursiya}}, [[aramî]] {{g|arc|כרסא|tr=kursa}} û {{g|arc|כסא|tr=kusa}}, îbranî {{ge|he|כיסא|tr=kissê}}, ugarîtî [[𐎋𐎒𐎜]] (kisủ), akadî [[𒄖𒍝]] / [[𒄑𒄖𒍝]] (kussû, kursû)... hemû ji {{ji|sux|ku|𒄖𒍝|tr=gu.za}}.
Peyv ji Rojhilata Navîn belav bûye Başûrê Asyayê jî: ûrdûyî {{g|ur|کرسی|tr=kursī}}, peştûyî {{g|ps|کورسۍ|tr=kursiy}}, hindî [[कुरसी]] (kursī), punjabî [[ਕੁਰਸੀ]] (kursī)...
;{{biçûk|Çavkanî:
* {{kitêb|sernavê orjînalThe Pennsylvania Sumerian Dictionary|sernav=Ferhenga sûmerî ya Pennsylvaniayê|url=http://psd.museum.upenn.edu/nepsd-frame.html}}
* {{kitêb|url=http://www.assyrianlanguages.org/akkadian/dosearch.php?searchkey=16&language=id|sernav=Rêkxistina Aşûrîdostan ya Fransayê: Ferhenga akadî|sernavê orjînal='Association Assyrophile de France: Dictionnaire akkadien}}
}}
==== Werger ====
{{werger-ser}}
* {{Z|af}}: {{W-|af|stoel}}
* {{Z|sq}}: {{W-|sq|karrike|m}}, {{W+|sq|karrige}}
* {{Z|de}}: {{W+|de|Stuhl|n}}
* {{Z|ast}}: {{W+|ast|siella}}
* {{Z|az}}: {{W+|az|stul}}
* {{Z|eu}}: {{W+|eu|aulki}}
* {{Z|bar}}: {{W--|bar|Sessl|n}}
* {{Z|be}}: {{W-|be|стул|tr=stul}}
* {{Z|br}}: {{W+|br|kador|m}}
* {{Z|bg}}: {{W+|bg|стол|tr=stol}}
* {{Z|cs}}: {{W+|cs|židle}}
* {{Z|zh}}: {{W+|zh|椅子|tr=yǐzi}}
* {{Z|da}}: {{W+|da|stol}}
* {{Z|id}}: {{W+|id|kursi}}
* {{Z|ary}}: {{W--|ary|كرسي}}, {{W--|ary|شلية}}
*: {{Z|arz}}: {{W|arz|كرسي|tr=kursî}} {{n}}
* {{Z|ar}}: {{W|ar|كرسي|tr=kursiyy}} {{n}}, {{W|ar|مقعد|tr=meq'ed}} {{n}}
* {{Z|hy}}: {{W+|hy|աթոռ|tr=atʿoṙ}}
* {{Z|eo}}: {{W+|eo|seĝo}}
* {{Z|et}}: {{W+|et|tool}}
* {{Z|ewo}}: {{W--|ewo|etoa}}
* {{Z|fa}}: {{W+|fa|صندلی|tr=sendelî}}, {{W|fa|کرسی|tr=korsî}}
* {{Z|fo}}: {{W-|fo|stólur}}
* {{Z|fi}}: {{W+|fi|tuoli}}, {{W|fi|istuin}}
* {{Z|frp}}: ''(savoyard)'' {{W--|frp|sala}}
* {{Z|fr}}: {{W|fr|chaise}}
* {{Z|fy}}: {{W-|fy|stoel}}, {{W-|fy|belech}}
* {{Z|gd}}: {{W-|gd|suidheachan}}, {{W-|gd|cathair}}
* {{Z|gl}}: {{W+|gl|cadeira|m}}
* {{Z|ka}}: {{W+|ka|სკამი|tr=sḳami}}
* {{Z|hi}}: {{W+|hi|कुरसी|tr=kursī}}
* {{Z|nl}}: {{W+|nl|stoel}}, {{W+|nl|zetel}}
* {{Z|he}}: {{W+|he|כיסא|tr=kisé}}
* {{Z|io}}: {{W+|io|stulo}}
* {{Z|ang}}: {{W-|ang|stol}}
* {{Z|en}}: {{W+|en|chair}}, {{W+|en|seat}}
* {{Z|ga}}: {{W+|ga|cathaoir}}
* {{Z|it}}: {{W+|it|assedio}}, {{W+|it|sedia}}, {{W+|it|seggiola}}
* {{Z|is}}: {{W+|is|stóll}}
* {{Z|ja}}: {{W+|ja|椅子|tr=isu}}, {{W+|ja|いす|tr=isu}}
* {{Z|ca}}: {{W+|ca|cadira}}
* {{Z|ki}}: {{W--|ki|giti}}
* {{Z|ko}}: {{W+|ko|의자|tr=uija}}
* {{Z|kw}}: {{W-|kw|cadar}}
* {{Z|co}}: {{W+|co|sedia}}, {{W-|co|carreca}}
* {{Z|mfe}}: {{W--|mfe|sez}}
* {{Z|la}}: {{W-|la|sella}}, {{W-|la|cathedra}}, {{W-|la|solium}}
* {{Z|lv}}: {{W+|lv|krēsls}}
* {{Z|lo}}: {{W+|lo|ຕັ່ງ}}
* {{Z|lt}}: {{W+|lt|kėdė}}
* {{Z|mk}}: {{W-|mk|стол|tr=stol}}, {{W-|mk|столица|tr=stolica}}
* {{Z|mg}}: {{W+|mg|seza}}
* {{Z|ms}}: {{W+|ms|kursi}}
* {{Z|mt}}: {{W+|mt|siġġu}}
* {{Z|gv}}: {{W-|gv|caair}}
* {{Z|yua}}: {{W--|yua|k’anche’}}
* {{Z|hu}}: {{W+|hu|szék}}
* {{Z|mn}}: {{W+|mn|сандал|tr=sandal}}
* {{Z|nrf}}: {{W--|nrf|caire}}
* {{Z|no}}: {{W+|no|stol|nt}}
* {{Z|oc}}: {{W+|oc|cadièra|m}}
* {{Z|uz}}: {{W+|uz|o`rindiq}}
* {{Z|uz}}: {{W|uz|o`rindiq}}
* {{Z|pap}}: {{W--|pap|stul}}
* {{Z|pl}}: {{W+|pl|krzesło}}
* {{Z|pt}}: {{W+|pt|cadeira|m}}, {{W+|pt|assento}}
* {{Z|kk}}: {{W+|kk|орындық|tr=orındıq}}, {{W-|kk|отырғыш|tr=otırğış}}
* {{Z|ro}}: {{W+|ro|scaun}}
* {{Z|ru}}: {{W+|ru|стул}}
* {{Z|se}}: {{W--|se|stuollu}}
* {{Z|srn}}: {{W--|srn|sturu}}
* {{Z|sh}}:
:* Latînî: {{W+|sh|stolac}}, {{W+|sh|stolica}}
:* Kirîlî: {{W-|sh|столац}}, {{W+|sh|столица}}
* {{Z|sk}}: {{W-|sk|stolička}}
* {{Z|sl}}: {{W+|sl|stol}}
* {{Z|dsb}}: {{W--|dsb|stoł}}
* {{Z|hsb}}: {{W-|hsb|stólc}}
* {{Z|es}}: {{W+|es|silla|m}}
* {{Z|sw}}: {{W+|sw|kiti}}
* {{Z|sv}}: {{W+|sv|stol}}
* {{Z|shy}}: {{W--|shy|amɣim}}
* {{Z|zdj}}: {{W--|zdj|hiri}}
* {{Z|tg}}: {{W-|tg|сандали|tr=sandali}}, {{W+|tg|курсӣ|tr=kursī}}
* {{Z|tl}}: {{W-|tl|sílya}}, {{W-|tl|úpuan}}
* {{Z|ta}}: {{W+|ta|நாற்காலி|tr=nāṟkāli}}
* {{Z|th}}: {{W+|th|เก้าอี้|tr=gâo-îi}}
* {{Z|tr}}: {{W+|tr|sandalye}}, {{W|tr|sandalye}}, {{W|tr|kürsü}}, {{W|tr|koltuk}}, {{W|tr|iskemle}}, {{W|tr|oturak}}, {{W|tr|tabure}}, {{W|tr|sekmen}}
* {{Z|tk}}: {{W-|tk|oturgyç}}
* {{Z|ur}}: {{W-|ur|کرسی|tr=kursī}}
* {{Z|ur}}: {{W|ur|کرسی|tr=kursī}} {{n}}
* {{Z|uk}}: {{W+|uk|стілець|tr=stilécʹ}}, {{W-|uk|крісло|tr=kríslo}}
* {{Z|vec}}: {{W|vec|carega}}
* {{Z|vi}}: {{W|vi|ghế}}
* {{Z|cy}}: {{W+|cy|cadair}}
* {{Z|cy}}: {{W|cy|cadair}}, {{W|cy|ystôl}}
* {{Z|km}}: {{W+|km|កៅអី|tr=kav ’əy}}
* {{Z|yi}}: {{W|yi|שטול}}
* {{Z|el}}: {{W+|el|καρέκλα|tr=karékla}}
* {{Z|el}}: {{W|el|καρέκλα}} {{n}} (karékla)
* {{Z|zu}}: {{W+|zu|isihlalo}}
{{werger-bin}}
== {{ziman|ckb}} ==
=== Navdêr ===
{{navdêr|ckb|sc=Latn}}
# {{ckb-Arab|کورسی}}
== {{ziman|zza}} ==
=== Navdêr ===
{{navdêr|zza}}
# [[kursî#Kurmancî|kursî]]
#* {{bêmînak|zza}}
2j2mrf0fvazg0zjofoyddl4v1z8xdre
şofêr
0
21051
6241704
6229915
2026-07-11T23:42:29Z
Wikihez
7344
/* Herwiha */
6241704
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|şofêr|mê û nêr}}
[[Wêne:Driver_Dave_Marshall_The_Friendly_Bus_Driver.jpg|thumb|'''Şofêrê''' [[otobûs]]an.]]
{{navdêr|ku|z=mn}}
# {{e|ku|meslek}} Kesê ku tiştekî [[ajotin|diajo]] (xisûsen [[erebe]]yekê).
#: {{hevmaneyên peyvê|ku|ajovan|ajokar|sayêq}}
#: {{nm|ku|Ew '''şofêrê''' taksiyê ye.}}
==== Bi alfabeyên din ====
* {{ku-ar|شۆفێر}}
==== Herwiha ====
* {{g|ku|şofer}}
* {{g|ku|şoferr}}
* {{g|ku|şofêrr}}
* {{g|ku|şifêr}}
==== Jê ====
* {{g|ku|şofêrî}}
* {{g|ku|şofêrîtî}}
* {{g|ku|şofêrtî}}
==== Etîmolojî ====
Ji {{deyn|fr|ku|chauffeur}}.
==== Werger ====
{{werger-ser}}
* {{Z|sq}}: {{W+|sq|shofer|n}}, {{W-|sq|makinist|n}}
* {{Z|de}}: {{W+|de|Fahrer|n}}, {{W+|de|Fahrerin|m}}
* {{Z|az}}: {{W+|az|sürücü}}, {{W-|az|şofer}}, {{W-|az|ranəndə}}
* {{Z|be}}: {{W-|be|кіро́ўца|n}}, {{W-|be|вадзі́цель|n}}, {{W-|be|шафёр|n}}
* {{Z|bcl}}: {{W-|bcl|drayber}}
* {{Z|bg}}: {{W+|bg|шофьо́р|n}}
* {{Z|my}}: {{W+|my|ယာဉ်မောင်း}}
* {{Z|cs}}: {{W+|cs|řidič|n}}, {{W+|cs|řidička|m}}, {{W+|cs|šofér|n}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|司機}}, {{W-|yue|駕駛員}}, {{W-|yue|駕駛者}}, {{W-|yue|柴可夫}}
*: {{Z|cmn}}: {{W+|cmn|司機}}, {{W+|cmn|駕駛員}}, {{W-|cmn|駕駛者}}
* {{Z|da}}: {{W+|da|chauffør|g}}
* {{Z|id}}: {{W+|id|sopir}}
* {{Z|ar}}: {{W+|ar|سائق|cuda=سَائِق|n}}, {{W-|ar|سَوَّاق|n}}
*: {{Z|arz}}: {{W-|arz|سواق|n|tr=sawwāʔ}}
*: {{Z|acw}}: {{W-|acw|سَوَّاق|n|tr=sawwāg}}
* {{Z|hy}}: {{W+|hy|վարորդ}}
* {{Z|eo}}: {{W-|eo|aŭtomobilisto}}, {{W-|eo|aŭtisto}}
* {{Z|et}}: {{W+|et|juht}}, {{W-|et|autojuht}}
* {{Z|fa}}: {{W+|fa|راننده|tr=rânande}}, {{W+|fa|شوفر|tr=šôfer}}, {{W-|fa|موترران|tr=motarrân}}
* {{Z|fo}}: {{W-|fo|bilførari|n}}, {{W-|fo|bussførari|n}}, {{W-|fo|motorsúkklistur|n}}, {{W-|fo|lastbilførari|n}}
* {{Z|fi}}: {{W+|fi|kuljettaja}}, {{W+|fi|ajaja}}, {{W+|fi|kuski}}
* {{Z|fr}}: {{W+|fr|conducteur|n}}, {{W+|fr|conductrice|m}}, {{W+|fr|chauffeur|n}}, {{W+|fr|chauffeuse|m}}
* {{Z|ka}}: {{W-|ka|მძღოლი}}
* {{Z|hi}}: {{W+|hi|चालक|n}}, {{W+|hi|ड्राइवर|n}}
* {{Z|nl}}: {{W+|nl|bestuurder|n}}, {{W+|nl|chauffeur|n}}
* {{Z|he}}: {{W+|he|נַהָג|n|tr=nahág}}, {{W+|he|נֶהָג|n|tr=nehág}}, {{W-|he|נהגת|m|tr=naheget}}
* {{Z|en}}: {{W+|en|driver}}
* {{Z|ga}}: {{W-|ga|tiománaí|n}}
* {{Z|it}}: {{W+|it|autista|n|m}}, {{W+|it|guidatore|n}}, {{W-|it|guidatrice|m}}
* {{Z|is}}: {{W-|is|ökumaður|n}}, {{W-|is|bílstjóri|n}}
* {{Z|ja}}: {{W+|ja|運転手|tr=うんてんしゅ, untenshu}}, {{W+|ja|運転者|tr=うんてんしゃ, untensha}}, {{W+|ja|ドライバ|tr=doraiba}}, {{W+|ja|ドライバー|tr=doraibā}}
* {{Z|kl}}: {{W-|kl|biilertoq}}
* {{Z|ca}}: {{W+|ca|conductor|n}}, {{W+|ca|xofer|n}}, {{W+|ca|xòfer|n}}
* {{Z|ky}}: {{W-|ky|жүргүзүүчү}}, {{W+|ky|айдоочу}}, {{W+|ky|шофёр}}
* {{Z|swb}}: {{W-|swb|shofera|c5|c6}}
* {{Z|ko}}: {{W+|ko|운전사}}, {{W+|ko|운전자}}, {{W+|ko|기사}}, {{W+|ko|운전기사}}, {{W+|ko|드라이버}}
* {{Z|la}}: {{W-|la|auriga|n}}
* {{Z|lv}}: {{W+|lv|vadītājs|n}}, {{W-|lv|šoferis|n}}
* {{Z|lo}}: {{W-|lo|ຄົນຂັບລົດ}}
* {{Z|lt}}: {{W-|lt|vairuotojas|n}}, {{W-|lt|šoferis|n}}
* {{Z|mk}}: {{W-|mk|возач|n}}, {{W-|mk|шофер|n}}
* {{Z|ms}}: {{W+|ms|pemandu}}, {{W-|ms|drebar}}
* {{Z|mt}}: {{W-|mt|sewwieq|n}}, {{W-|mt|sewwieqa|m}}, {{W-|mt|xufier|n}}, {{W-|mt|xufiera|m}}
* {{Z|mi}}: {{W-|mi|kaitaraiwa}}
* {{Z|mr}}: {{W-|mr|चालक|n}}, {{W-|mr|चालिका|m}}
* {{Z|hu}}: {{W+|hu|sofőr}}, {{W+|hu|vezető}}, {{W+|hu|járművezető}}, {{W+|hu|gépjárművezető}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|жолооч}}
* {{Z|nrf}}: {{W-|nrf|cacheux|n}}
* {{Z|no}}:
*: {{Z|nb}}: {{W-|nb|fører|n}}, {{W+|nb|sjåfør|n}}
*: {{Z|nn}}: {{W-|nn|førar|n}}, {{W-|nn|sjåfør|n}}
* {{Z|ug}}: {{W-|ug|شوپۇر}}
* {{Z|uz}}: {{W+|uz|haydovchi}}, {{W+|uz|shofyor}}
* {{Z|ps}}: {{W-|ps|ډرايور|n|tr=ḍrāywar}}, {{W-|ps|ډرېور|n|tr=ḍrewar}}, {{W-|ps|موټروان|n|tr=moṭarwān}}
* {{Z|pl}}: {{W+|pl|kierowca|n}}, {{W+|pl|szofer|n}}, {{W+|pl|automobilista|n}}, {{W-|pl|automobilistka|m}}
* {{Z|pt}}: {{W+|pt|motorista|n|m}}, {{W+|pt|condutor|n}}, {{W+|pt|condutora|m}}
* {{Z|kk}}: {{W+|kk|жүргізуші}}, {{W-|kk|шопыр}}
* {{Z|ro}}: {{W+|ro|șofer|n}}, {{W-|ro|conducător auto|n}}
* {{Z|ru}}: {{W+|ru|води́тель|n}}, {{W+|ru|води́тельница|m}}, {{W+|ru|шофёр|n}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|во̀за̄ч|n}}, {{W-|sh|воза̀чица|m}}
*: Latînî: {{W+|sh|vòzāč|n}}, {{W+|sh|vozàčica|m}}
* {{Z|sk}}: {{W-|sk|vodič|n}}, {{W-|sk|šofér|n}}
* {{Z|sl}}: {{W+|sl|voznik|n}}, {{W-|sl|šofer|n}}
* {{Z|es}}: {{W+|es|conductor|n}}, {{W-|es|conductora|m}}, {{W+|es|chofer|n}}
* {{Z|sw}}: {{W+|sw|dereva}}
* {{Z|sv}}: {{W+|sv|förare|g}}, {{W+|sv|chaufför|g}}
* {{Z|tg}}: {{W+|tg|ронанда}}, {{W+|tg|шофёр}}
* {{Z|tl}}: {{W+|tl|drayber}}
* {{Z|tl}}: {{W+|tl|drayber}}
* {{Z|th}}: {{W-|th|คนขับรถ}}, {{W-|th|คนขับ}}
* {{Z|te}}: {{W+|te|చోదకుడు}}
* {{Z|tr}}: {{W+|tr|sürücü}}, {{W+|tr|şoför}}, {{W-|tr|haydavcı}}, {{W-|tr|yöndemci}}, {{W-|tr|kıvcı}}
* {{Z|tk}}: {{W-|tk|sürügi}}, {{W-|tk|şofýor}}
* {{Z|bo}}: {{W-|bo|ཁ་ལོ་བ}}
* {{Z|ur}}: {{W-|ur|ڈرائیور|n|tr=ḍrāivar}}
* {{Z|uk}}: {{W-|uk|воді́й|n}}, {{W-|uk|шофе́р|n}}
* {{Z|vi}}: {{W-|vi|người lái}}, {{W+|vi|tài xế}}
* {{Z|cy}}: {{W+|cy|gyrrwr|n}}
* {{Z|km}}: {{W-|km|អ្នកបើកឡាន}}, {{W-|km|តៃកុង}}
* {{Z|yi}}: {{W-|yi|שאָפֿער|n}}
* {{Z|el}}: {{W+|el|οδηγός|n|m}}
{{werger-bin}}
:{{werger çavkanî|en|driver|beş=Ev qismê Wergerê|oldid=75869153}}
jm4voyu9o89nr73gxjd13kcyokrmz6d
burs
0
21998
6241719
6035781
2026-07-12T00:18:37Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241719
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|burs|mê}}
{{navdêr|ku|z=m}}
# [[meblex|Meblex]]ek [[dirav]]î ya [[dewlet]] yan [[dezgeh]]ek wek [[diyarî]] dide [[xwendekar]]ekî (bi taybetî ji ber [[biserketî]]bûnê).
#: {{hevmaneyên peyvê|ku|stîpend|dermale}}
#* {{jêder|ku|jêgirtin=Şaredariya Amedê dê '''burs''' bide 50 hezar zarokan|Kurdishinfo.com, 7/2006}}
==== Jê ====
* {{g|ku|bursdar}}
* {{g|ku|bursder}}
* {{g|ku|bursiyer}}
==== Etîmolojî ====
Ji {{deyn|fr|ku|bourse}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Stipendium}} {{n}}
* {{Z|fi}}: {{W+|fi|stipendi}}
* {{Z|fr}}: {{W+|fr|bourse}}, [[érudition]]
* {{Z|io}}: {{W+|io|stipendio}}, [[erud-it-eso]]
* {{Z|en}}: {{W+|en|scholarship}}, [[bursary]], [[grant-in-aid]]
* {{Z|it}}: {{W+|it|borsa|m}} (di studi)
* {{Z|sv}}: {{W+|sv|stipendium}}
* {{Z|tr}}: {{W+|tr|burs}}
{{werger-bin}}
== {{ziman|tr}} ==
=== Bilêvkirin ===
* {{deng|tr|LL-Q256 (tur)-ToprakM-burs.wav|Deng|dever=Îzmîr, Tirkiye}}
=== Navdêr ===
{{navdêr|tr}}
# [[burs#Kurdî|burs]], [[stîpend]]
#* {{bêmînak|tr}}
pv6iw5s1pdoms9yk7iu3ypb2biuqkrf
wize
0
23990
6241707
6068219
2026-07-11T23:44:47Z
Wikihez
7344
/* Jê */
6241707
wikitext
text/x-wiki
{{bnr-h|wîze}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/wɪˈzɛː/}}
* {{kîte|ku|wi|ze}}
=== Navdêr ===
{{ku-tewîn-nav|wize|mê|guherto=hemû}}
{{navdêr|ku|z=m}}
# [[enerjî]], [[vejen]], [[hêz]], [[xurtî]], [[hinêr]], [[taqet]], [[şiyan]], [[qewet]], [[jen]], [[liv]], [[lebat]], [[hereket]]
#* {{jêder|ku|jêgirtin=Di gotara xwe de ya bi navê ’Du calcul de l'effet des machines’ [Gaspard Gustave de Coriolis] di sala 1829an de pênasînên nûjen (modern definition) yên kar û '''wizeya''' livînî (kinetic energy) danîn.|Zagrosê Hajo: ''Bandora hêza Coriolis çi ye?'', Netkurd.com, 8/2006}}
# {{kontrol|rêz=erê|[[hiz]], [[qudret]]}}
==== Herwiha ====
* [[vize]]
* [[wuze]]
==== Jê ====
{{kol3|ku|cure=Jê
|bêwize
|bêwizehî
|bêwizetî
|bêwizeyî
|biwize
|wizedar
|wizedarî
|wizedarîtî
|wizedartî
|wizeyî
}}
==== Etîmolojî ====
Ji {{deyn|ckb|ku|وزە}}, hevreha {{hv|ku|hizî|w=taqet, wize}}, ji {{paş|ku|hêz|-e}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Energie}} {{m}}
* {{Z|ar}}: {{W+|ar|طاقة}}
* {{Z|fa}}: {{W+|fa|انرژی}}, {{W+|fa|طاقت}}
* {{Z|en}}: {{W+|en|energy}}, {{W+|en|moxie}}
* {{Z|tr}}: {{W+|tr|enerji}}, {{W+|tr|erke}}, {{W+|tr|performans}}
{{werger-bin}}
3clgpbn8vke46lc0q02wm62yzz2qfo0
6241708
6241707
2026-07-11T23:45:13Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241708
wikitext
text/x-wiki
{{bnr-h|wîze}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/wɪˈzɛː/}}
* {{kîte|ku|wi|ze}}
=== Navdêr ===
{{ku-tewîn-nav|wize|mê|guherto=hemû}}
{{navdêr|ku|z=m}}
# [[enerjî]], [[vejen]], [[hêz]], [[xurtî]], [[hinêr]], [[taqet]], [[şiyan]], [[qewet]], [[jen]], [[liv]], [[lebat]], [[hereket]]
#* {{jêder|ku|jêgirtin=Di gotara xwe de ya bi navê ’Du calcul de l'effet des machines’ [Gaspard Gustave de Coriolis] di sala 1829an de pênasînên nûjen (modern definition) yên kar û '''wizeya''' livînî (kinetic energy) danîn.|Zagrosê Hajo: ''Bandora hêza Coriolis çi ye?'', Netkurd.com, 8/2006}}
# {{kontrol|rêz=erê|[[hiz]], [[qudret]]}}
==== Herwiha ====
* [[vize]]
* [[wuze]]
==== Jê ====
{{kol3|ku|cure=Jê
|bêwize
|bêwizehî
|bêwizetî
|bêwizeyî
|biwize
|wizedar
|wizedarî
|wizedarîtî
|wizedartî
|wizeyî
}}
==== Etîmolojî ====
Ji {{deyn|ckb|ku|وزە}}, hevreha {{hv|ku|hizî|w=taqet, wize}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Energie}} {{m}}
* {{Z|ar}}: {{W+|ar|طاقة}}
* {{Z|fa}}: {{W+|fa|انرژی}}, {{W+|fa|طاقت}}
* {{Z|en}}: {{W+|en|energy}}, {{W+|en|moxie}}
* {{Z|tr}}: {{W+|tr|enerji}}, {{W+|tr|erke}}, {{W+|tr|performans}}
{{werger-bin}}
2s44iw7vswzohgat15cpdfrlbcyvraj
Alîkarî:Nivîsîn
12
25550
6241747
4014723
2026-07-12T11:49:31Z
Kewkûrk
15130
Min naveroka gotara heyî zêdekir.
6241747
wikitext
text/x-wiki
== dêrtin ==
=== Kurdî Kurmancî ===
==== Etîmolojî ====
Dêrtin/dartin lêkerekî kevn ê kurmancî ye ku wateyên wê bingehîn ev in: xwedî bûn, hebûn, girtin û parastin.
Ji rehê kevn ê îranî tê, ku bi farisî **داشتن (dâštan)** ("hebûn, xwedî bûn, girtin") hevreha ye.
Ji rehê proto-hindû-ewropî **\*dʰer-** tê, ku wateya bingehîn ya wê "girtina bi hêz, ragirtin, domandin" e.
Hevrehên din:
* farisiya kevn: 𐎭𐎠𐎼𐎹𐎫𐎡𐎹 (dārayatiy) — "digire, xwedî ye"
* farisiya navîn: dāštan
* farisî: داشتن (dâštan)
==== Lêker ====
===== Wate =====
# xwedî bûn, hebûn
# girtin, ragirtin
# xwedîkirin, xwedî derketin
==== Di zimanê kurmancî de ====
Lêkerê dêrtin/dartin di axaftina rojane ya kurmanciya nûjen de kêm hatiye bikaranîn û di gelemperî de bi lêkerên **hebûn** û **xwedî bûn** hatiye guherandin.
Lêbelê rehê wê di nav peyvên çêkirî de hîn jî dijî:
* **maldar** — kesê ku mal heye
* **deyndar** — kesê ku deyn heye
* **birîndar** — kesê ku birîn heye
* **çavdêr** — kesê ku çavdêrî dike
* **nobedar** — kesê ku nobet digire
* **dîndar** — kesê ku dîn heye
* **namûsdar** — kesê ku namûs heye
* **ahengdar** — kesê ku aheng heye
* **rengdar** — tiştê ku reng heye; reng lê ye
* **bangdêr** — kesê ku bang dike
Paşgirên **-dar/-dêr** maneya "xwedîbûn, hilgirtin, ragirtin" diparêzin.
==== Tevgerandin ====
===== Dema niha =====
{| class="wikitable"
! Kes
! Form
|-
| Ez || didêrim
|-
| Tu || didêrî
|-
| Ew/ewa || didêre
|-
| Em || didêrin
|-
| Hûn || didêrin
|-
| Ewna || didêrin
|}
===== Borî ya sade =====
{| class="wikitable"
! Kes
! Form
|-
| Min || dêrî
|-
| Te || dêrî
|-
| Wî || dêrî
|-
| Wê || dêrî
|-
| Me || dêrî
|-
| Wan || dêrî
|}
===== Borî ya nedîyar / berdewam =====
{| class="wikitable"
! Kes
! Form
|-
| Min || didêrî
|-
| Te || didêrî
|-
| Wî || didêrî
|-
| Wê || didêrî
|-
| Me || didêrî
|-
| We || didêrî
|-
| Wan || didêrî
|}
===== Dema pêşerojê =====
{| class="wikitable"
! Kes
! Form
|-
| Ez || dê bidêrim
|-
| Tu || dê bidêrî
|-
| Ew/ewa || dê bidêre
|-
| Em || dê bidêrin
|-
| Hûn || dê bidêrin
|-
| Ewna || dê bidêrin
|}
5g8s197dgu01wg62h3xggo7virmwz3y
6241749
6241747
2026-07-12T11:54:40Z
Wikihez
7344
Reverted 1 edit by [[Special:Contributions/Kewkûrk|Kewkûrk]] ([[User talk:Kewkûrk|talk]]): Ji kerema xwe bar bike [[dêrtin]] ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241749
wikitext
text/x-wiki
{{guherrandin}}
Çêkirina rûpelên nû gelek hêsan e.
== Rengê sor nîşana tinebûna rûpelê dike ==
Dema ku tu li peyvê bigerî û nebînî, hingê Wîkîferheng dê peyvê bi rengê '''{{reng2|#d33|sor}}''' binivîse û bibêje ku rûpel bi wî navî tune ye.
Her peyva bi rengê sor tê wê wateyê ku ti rûpel bi wî navî tune ye.
Pêlî wê peyva rengsor bike û dest bi nivîsîna wê bike. Bala xwe bide ku li şûna peyvên devokî peyvên standard û li her derê tê zanîn bi kar bînî.
Ji bo formatê ''binêre'':
* '''[[Alîkarî:Formata nivîsînê]]'''
* '''[[Alîkarî:Cureyên peyvan]]'''
[[Kategorî:Alîkarî]]
df2evjlhg9ugbu3yaxn6zgd13lhfdgc
zîz bûn
0
37865
6241643
5908735
2026-07-11T18:10:20Z
Keyomerd
8814
/* Kurmancî */
6241643
wikitext
text/x-wiki
{{bnr-n|zîzbûn}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker 1 ===
{{ku-tewîn-lk|zîz bûn|form=negerguhêz|niha=b|borî=bû|pêşgir=zîz|valahî=erê}}
{{lêker|ku|c=h-ngh}}
# {{mane?|ku}}
#* {{bêmînak|ku}}
==== Etîmolojî ====
Ji {{heve|ku|zîz|bûn}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|sulk|guman=erê}}
* {{Z|tr}}: {{W+|tr|acılaşmak}}, {{W+|tr|duygulanmak}}, {{W-|tr|duygusallaşmak}}
{{werger-bin}}
=== Lêker 2 ===
{{lêker|ku|c=h-ngh}}
# Li dora tiştekî [[zivirîn]].
==== Jê ====
* {{g|ku|zîzok}}
==== Etîmolojî ====
Ji {{heve|ku|zîz|bûn}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|spin}}
{{werger-bin}}
tpcnj5vjwgprtfbhhxvgfmvsdz0wusr
6241645
6241643
2026-07-11T18:11:21Z
Keyomerd
8814
/* Lêker 2 */
6241645
wikitext
text/x-wiki
{{bnr-n|zîzbûn}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker 1 ===
{{ku-tewîn-lk|zîz bûn|form=negerguhêz|niha=b|borî=bû|pêşgir=zîz|valahî=erê}}
{{lêker|ku|c=h-ngh}}
# {{mane?|ku}}
#* {{bêmînak|ku}}
==== Etîmolojî ====
Ji {{heve|ku|zîz|bûn}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|sulk|guman=erê}}
* {{Z|tr}}: {{W+|tr|acılaşmak}}, {{W+|tr|duygulanmak}}, {{W-|tr|duygusallaşmak}}
{{werger-bin}}
=== Lêker 2 ===
{{lêker|ku|c=h-ngh}}
# {{maneid|ku|spin}} Li dora tiştekî [[zivirîn]].
==== Jê ====
* {{g|ku|zîzok}}
==== Etîmolojî ====
Ji {{heve|ku|zîz|bûn}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|spin}}
{{werger-bin}}
mhv5llpzytk8z03j6icuqtbt4bwsp6l
6241647
6241645
2026-07-11T18:13:38Z
Keyomerd
8814
/* Lêker 2 */
6241647
wikitext
text/x-wiki
{{bnr-n|zîzbûn}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker 1 ===
{{ku-tewîn-lk|zîz bûn|form=negerguhêz|niha=b|borî=bû|pêşgir=zîz|valahî=erê}}
{{lêker|ku|c=h-ngh}}
# {{mane?|ku}}
#* {{bêmînak|ku}}
==== Etîmolojî ====
Ji {{heve|ku|zîz|bûn}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|sulk|guman=erê}}
* {{Z|tr}}: {{W+|tr|acılaşmak}}, {{W+|tr|duygulanmak}}, {{W-|tr|duygusallaşmak}}
{{werger-bin}}
=== Lêker 2 ===
{{lêker|ku|c=h-ngh}}
# {{maneid|ku|spin}} Li dora tiştekî [[zivirîn]].
#: {{hevmane|ku|çerixîn}}
==== Jê ====
* {{g|ku|zîzok}}
==== Etîmolojî ====
Ji {{heve|ku|zîz|bûn}}.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|spin}}
{{werger-bin}}
g0i7kma66cpby0bb2xpb57x87g8mz96
ding
0
38625
6241723
6134237
2026-07-12T01:20:14Z
Wikihez
7344
/* Jê */
6241723
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|ding|mê}}
{{navdêr|ku|z=m}}
# [[deng|Deng]]ekî [[xurt]] lê [[ketin]]ê yan [[lêdan]]ê.
#* {{bêmînak|ku}}
==== Jê ====
{{kol3|ku|cure=Jê
|ding kirin<q:lêker>
|dingkirin<q:navdêr>
|dingkirî<q:rengdêr>
|dinge-ding
|dingandin
|dingîn
}}
==== Nêzîk ====
* {{g|ku|diring}}
* {{g|ku|ting}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W|fa|دیوار محکم}}, {{W|fa|صدای دُهُل}}
* {{Z|en}}: {{W|en|gum}}, {{W|en|ring}}, {{W|en|mainstay|guman=erê}}, {{W|en|spile|guman=erê}}, {{W|en|staddle|guman=erê}}, {{W|en|underpinning|guman=erê}}, {{W|en|spiling|guman=erê}}
* {{Z|tr}}: {{W|tr|dink}}, {{W|tr|ring}}, {{W|tr|balya}}, {{W|tr|bağlamak}}, {{W|tr|denk|guman=erê}}
{{werger-bin}}
== {{ziman|af}} ==
=== Navdêr ===
{{navdêr|af}}
# {{g|ku|tişt}}
#* {{bêmînak|af}}
=== Çavkanî ===
{{rûpela wergerê|af|tişt}}
== {{ziman|fy}} ==
=== Navdêr ===
{{navdêr|fy|z=nt}}
# {{g|ku|tişt}}
#* {{bêmînak|fy}}
=== Çavkanî ===
{{rûpela wergerê|fy|tişt}}
== {{ziman|nl}} ==
=== Navdêr ===
{{navdêr|nl|z=nt}}
# {{g|ku|tişt}}
#* {{bêmînak|nl}}
=== Çavkanî ===
{{rûpela wergerê|nl|tişt}}
== {{ziman|en}} ==
=== Lêker ===
{{lêker|en}}
# [[zengil lê dan]]
#* {{bêmînak|en}}
=== Navdêr ===
{{navdêr|en}}
# dengê zengilê<ref>Ferhenga Kurdî-Îngîlîzî ya Salah Sadallah</ref>
#* {{bêmînak|en}}
=== Çavkanî ===
{{çavkanî}}
sdjm0cfsi8ji08oefj32kdnoy8iqexs
çerixîn
0
39428
6241646
6124700
2026-07-11T18:13:11Z
Keyomerd
8814
/* Lêker */
6241646
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Lêker ===
{{ku-tewîn-lk|çerixîn|form=negerguhêz|niha=çerix|borî=çerix}}
{{lêker|ku|c=x-ngh}}, {{ç-ya req}}, {{r-ya nerm}}
# {{g|ku|zîz bûn|id=spin}}, [[çerx]] dan, [[dewr]] dan, li [[dor]] tiştekî [[zivirîn]]
#* {{jêder|ku|jêgirtin=Heta refên valahiyê jî di nav bêdengiya xwe de '''diçerixîn''' û gêr dibûn.|{{Jêgirtin/Mehmed Uzun/Mirina Kalekî Rind/1987}}}}
# {{f|ku|Qoser}} [[şemitîn]]
#* {{bêmînak|ku}}
==== Ji wêjeya klasîk ====
* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Bihnek ji wisalê me bihîst û kerixîm ez</br>Wek tole li pê mûçih li dorê '''çerixîm''' ez</br>Çix kir me hebîbî ko tu narî biqeşî}}
==== Bi alfabeyên din ====
* {{ku-ar|چهرخین}}
==== Herwiha ====
* [[çerxîn]]
==== Tewîn ====
''Lêker'':
:-çerix-
==== Têkildar ====
* [[çerxandin]]
==== Etîmolojî ====
Ji {{qertaf|ku|çerx|-în}}.
==== Jê ====
* [[çerixiyayî]]
* [[çerixî]]
* [[çerixok]]
==== Bi zaravayên din ====
* {{Z|ckb}}: {{W-|ckb|سووڕان}}, {{W-|ckb|چەرخان}}, {{W-|ckb|خولان}}, {{W-|ckb|خولانەوە}}, {{W-|ckb|خول خواردن}}
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|aufwirbeln}}
* {{Z|ar}}: {{W-|ar|أقبل|guman=erê}}
* {{Z|fa}}: {{W+|fa|چرخیدن}}, {{W+|fa|چرخیدن}}
* {{Z|en}}: {{W+|en|turn}}, {{W+|en|slipping}}, {{W+|en|sliding}}, {{W+|en|skidding}}
* {{Z|tr}}: {{W+|tr|deveran}}, {{W+|tr|dolaşmak}}, {{W+|tr|dönelemek}}, {{W+|tr|kaymak}}, {{W+|tr|sıyrılma}}, {{W+|tr|sıyrılmak}}, {{W+|tr|sürçme}}, {{W+|tr|sürçmek}}, {{W+|tr|deveran etmek|guman=erê}}, {{W-|tr|kendi ekseni etrafında dönmek|guman=erê}}
{{werger-bin}}
=== Navdêr ===
{{ku-tewîn-nav|çerixîn|mê}}
{{navdêr|ku|z=m}}
# {{bêwate}}
#* {{bêmînak|ku}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
kwqjvf57xcpud7iqdqrbq204b0ixcgn
zift
0
43774
6241666
6135107
2026-07-11T20:35:47Z
Wikihez
7344
[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin
6241666
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
[[Wêne:EPAoilspillsubdivision5.jpg|thumb|zift]]
{{navdêr|ku|z=m}}
# Tiştek [[reş]], [[çir]], [[ron]] û [[don]] e û bi taybetî bo [[ava]]kirina [[kolan]]an tê [[bikaranîn]].
#: {{hevmane|ku|qîr|qetran|asfalt}}
#* {{jêder|ku|jêgirtin=Li ser riya qîr û '''zift''' / Hatin ser hev pale gişt|{{Jêgirtin/Firat Cewerî/Çîroka Malbata Evdo/1999}}}}
# [[made|Made]]yê ku [[berî]] [[rê]]yekê [[qîr]] bikin [[danan|didanin]].
==== Jê ====
{{kol3|ku|cure=Jê
|zift kirin<pos:lêker>
|ziftkirin<pos:navdêr>
|ziftkirî<pos:rengdêr>
|ziftbûyî<pos:rengdêr>
|ziftî
}}
==== Bi alfabeyên din ====
* {{ku-ar|زفت}}
==== Bide ber ====
* {{g|ku|zeft}}
==== Etîmolojî ====
Ji {{ji|ar|ku|زفت|tr=zift}} ji {{ji|arc|ku||zipta}}. Hevreha {{hv|akk||ziptu|sc=Latn}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Asphalt|n}}, {{W+|de|Bitumen|m|guman=erê}}
* {{Z|fa}}: {{W+|fa|آسفالت}}, {{W+|fa|قیر}}
* {{Z|en}}: {{W+|en|bitumen}}, {{W+|en|pitch}}, {{W+|en|tar}}
* {{Z|tr}}: {{W+|tr|asfalt}}, {{W+|tr|zabıt}}, {{W+|tr|zapt}}, {{W+|tr|zift}}
{{werger-bin}}
== {{ziman|tr}} ==
=== Navdêr ===
{{navdêr|tr}}
# [[qîr]], [[zift]]
#* {{bêmînak|tr}}
ecmdfjr2kp0qg02g6h523r9l13br3ye
6241667
6241666
2026-07-11T20:36:05Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241667
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
[[Wêne:EPAoilspillsubdivision5.jpg|thumb|zift]]
{{navdêr|ku|z=m}}
# Tiştek [[reş]], [[çir]], [[ron]] û [[don]] e û bi taybetî bo [[ava]]kirina [[kolan]]an tê [[bikaranîn]].
#: {{hevmane|ku|qîr|qetran|asfalt}}
#* {{jêder|ku|jêgirtin=Li ser riya qîr û '''zift''' / Hatin ser hev pale gişt|{{Jêgirtin/Firat Cewerî/Çîroka Malbata Evdo/1999}}}}
# [[made|Made]]yê ku [[berî]] [[rê]]yekê [[qîr]] bikin [[danan|didanin]].
==== Bi alfabeyên din ====
* {{ku-ar|زفت}}
==== Jê ====
{{kol3|ku|cure=Jê
|zift kirin<pos:lêker>
|ziftkirin<pos:navdêr>
|ziftkirî<pos:rengdêr>
|ziftbûyî<pos:rengdêr>
|ziftî
}}
==== Bide ber ====
* {{g|ku|zeft}}
==== Etîmolojî ====
Ji {{ji|ar|ku|زفت|tr=zift}} ji {{ji|arc|ku||zipta}}. Hevreha {{hv|akk||ziptu|sc=Latn}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Asphalt|n}}, {{W+|de|Bitumen|m|guman=erê}}
* {{Z|fa}}: {{W+|fa|آسفالت}}, {{W+|fa|قیر}}
* {{Z|en}}: {{W+|en|bitumen}}, {{W+|en|pitch}}, {{W+|en|tar}}
* {{Z|tr}}: {{W+|tr|asfalt}}, {{W+|tr|zabıt}}, {{W+|tr|zapt}}, {{W+|tr|zift}}
{{werger-bin}}
== {{ziman|tr}} ==
=== Navdêr ===
{{navdêr|tr}}
# [[qîr]], [[zift]]
#* {{bêmînak|tr}}
8741pokicn1oucbd3rji88vxibq9om0
asfalt
0
43775
6241657
6095491
2026-07-11T20:16:11Z
Wikihez
7344
/* Navdêr */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin
6241657
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{ku-tewîn-nav|asfalt|mê}}
{{navdêr|ku|z=m}}
# Tiştek [[reş]], [[çir]], [[ron]] û [[don]] e û bi taybetî bo [[ava]]kirina [[kolan]]an tê [[bikaranîn]].
#: {{hevmane|ku|qîr|qetran|zift}}
#* {{bêmînak|ku}}
==== Jê ====
{{kol3|ku|cure=Jê
|asfalt kirin<q:lêker>
|asfaltkirin<q:navdêr>
|asfaltî
}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|af}}: {{W-|af|asfalt}}, {{W-|af|bergpik}}
* {{Z|de}}: {{W+|de|Asphalt|m}}, {{W-|de|Erdpech}}
* {{Z|id}}: {{W+|id|aspal}}
* {{Z|eo}}: {{W+|eo|asfalto}}
* {{Z|fa}}: {{W+|fa|آسفالت}}
* {{Z|fi}}: {{W+|fi|asvaltti}}
* {{Z|fr}}: {{W+|fr|asphalte}}
* {{Z|nl}}: {{W+|nl|asfalt}}
* {{Z|he}}: {{W+|he|כֹּפֶר|tr=kfar}}
* {{Z|en}}: {{W+|en|asphalt}}, {{W+|en|blacktop}}
* {{Z|it}}: {{W+|it|asfalto}}
* {{Z|is}}: {{W-|is|asfalt}}, {{W+|is|malbik}}
* {{Z|ca}}: {{W+|ca|asfalt}}
* {{Z|la}}: {{W-|la|bitumen}}
* {{Z|hu}}: {{W+|hu|aszfalt}}
* {{Z|pap}}: {{W-|pap|asfalt}}
* {{Z|pt}}: {{W+|pt|asfalto}}
* {{Z|ru}}: {{W+|ru|асфальт}}
* {{Z|es}}: {{W+|es|asfalto}}
* {{Z|sv}}: {{W-|sv|jordbeck}}
* {{Z|tr}}: {{W+|tr|asfalt}}
* {{Z|el}}: {{W+|el|άσφαλτος}}
{{werger-bin}}
== {{ziman|tr}} ==
=== Bilêvkirin ===
* {{deng|tr|LL-Q256 (tur)-Veravi95-asfalt.wav|Deng|dever=}}
=== Navdêr ===
{{navdêr|tr}}
# [[qîr]]
#* {{bêmînak|tr}}
# [[qetran]], asfalt
#* {{bêmînak|tr}}
# [[asfaltkirî]]
#: {{mk|tr|uzun bir '''asfalt''' yol üzerinde koştuk|me li ser riyeke dirêj a asfatkirî baz dan}}
1pska8wwj1qtd5aa508n96hkky1v4fk
6241658
6241657
2026-07-11T20:17:05Z
Wikihez
7344
/* Navdêr */
6241658
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{ku-tewîn-nav|asfalt|mê}}
{{navdêr|ku|z=m}}
# Tiştek [[reş]], [[çir]], [[ron]] û [[don]] e û bi taybetî bo [[ava]]kirina [[kolan]]an tê [[bikaranîn]].
#: {{hevmane|ku|qîr|qetran|zift}}
#* {{bêmînak|ku}}
==== Jê ====
{{kol3|ku|cure=Jê
|asfalt kirin<q:lêker>
|asfaltkirin<q:navdêr>
|asfaltî
}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|af}}: {{W-|af|asfalt}}, {{W-|af|bergpik}}
* {{Z|de}}: {{W+|de|Asphalt|m}}, {{W-|de|Erdpech}}
* {{Z|id}}: {{W+|id|aspal}}
* {{Z|eo}}: {{W+|eo|asfalto}}
* {{Z|fa}}: {{W+|fa|آسفالت}}
* {{Z|fi}}: {{W+|fi|asvaltti}}
* {{Z|fr}}: {{W+|fr|asphalte}}
* {{Z|nl}}: {{W+|nl|asfalt}}
* {{Z|he}}: {{W+|he|כֹּפֶר|tr=kfar}}
* {{Z|en}}: {{W+|en|asphalt}}, {{W+|en|blacktop}}
* {{Z|it}}: {{W+|it|asfalto}}
* {{Z|is}}: {{W-|is|asfalt}}, {{W+|is|malbik}}
* {{Z|ca}}: {{W+|ca|asfalt}}
* {{Z|la}}: {{W-|la|bitumen}}
* {{Z|hu}}: {{W+|hu|aszfalt}}
* {{Z|pap}}: {{W-|pap|asfalt}}
* {{Z|pt}}: {{W+|pt|asfalto}}
* {{Z|ru}}: {{W+|ru|асфальт}}
* {{Z|es}}: {{W+|es|asfalto}}
* {{Z|sv}}: {{W-|sv|jordbeck}}
* {{Z|tr}}: {{W+|tr|asfalt}}
* {{Z|el}}: {{W+|el|άσφαλτος}}
{{werger-bin}}
== {{ziman|tr}} ==
=== Bilêvkirin ===
* {{deng|tr|LL-Q256 (tur)-Veravi95-asfalt.wav|Deng|dever=}}
=== Navdêr ===
{{navdêr|tr}}
# [[qîr]]
#* {{bêmînak|tr}}
# [[qetran]], {{g|ku|asfalt}}
#* {{bêmînak|tr}}
=== Rengdêr ===
{{rengdêr|tr}}
# [[asfaltkirî]]
#: {{mk|tr|uzun bir '''asfalt''' yol üzerinde koştuk.|Me li ser riyeke dirêj a asfatkirî baz dan.}}
6ykixsbiy2y50d006jcct2bofro9qk6
6241659
6241658
2026-07-11T20:17:26Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241659
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{ku-tewîn-nav|asfalt|mê}}
{{navdêr|ku|z=m}}
# Tiştek [[reş]], [[çir]], [[ron]] û [[don]] e û bi taybetî bo [[ava]]kirina [[kolan]]an tê [[bikaranîn]].
#: {{hevmane|ku|qîr|qetran|zift}}
#* {{bêmînak|ku}}
==== Jê ====
{{kol3|ku|cure=Jê
|asfalt kirin<q:lêker>
|asfaltkirin<q:navdêr>
|asfaltî
}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|af}}: {{W-|af|asfalt}}, {{W-|af|bergpik}}
* {{Z|de}}: {{W+|de|Asphalt|m}}, {{W-|de|Erdpech}}
* {{Z|id}}: {{W+|id|aspal}}
* {{Z|eo}}: {{W+|eo|asfalto}}
* {{Z|fa}}: {{W+|fa|آسفالت}}
* {{Z|fi}}: {{W+|fi|asvaltti}}
* {{Z|fr}}: {{W+|fr|asphalte}}
* {{Z|nl}}: {{W+|nl|asfalt}}
* {{Z|he}}: {{W+|he|כֹּפֶר|tr=kfar}}
* {{Z|en}}: {{W+|en|asphalt}}, {{W+|en|blacktop}}
* {{Z|it}}: {{W+|it|asfalto}}
* {{Z|is}}: {{W-|is|asfalt}}, {{W+|is|malbik}}
* {{Z|ca}}: {{W+|ca|asfalt}}
* {{Z|la}}: {{W-|la|bitumen}}
* {{Z|hu}}: {{W+|hu|aszfalt}}
* {{Z|pap}}: {{W-|pap|asfalt}}
* {{Z|pt}}: {{W+|pt|asfalto}}
* {{Z|ru}}: {{W+|ru|асфальт}}
* {{Z|es}}: {{W+|es|asfalto}}
* {{Z|sv}}: {{W-|sv|jordbeck}}
* {{Z|tr}}: {{W+|tr|asfalt}}
* {{Z|el}}: {{W+|el|άσφαλτος}}
{{werger-bin}}
== {{ziman|tr}} ==
=== Bilêvkirin ===
* {{deng|tr|LL-Q256 (tur)-Veravi95-asfalt.wav|Deng|dever=}}
=== Navdêr ===
{{navdêr|tr}}
# [[qîr]]
#* {{bêmînak|tr}}
# [[qetran]], {{g|ku|asfalt}}
#* {{bêmînak|tr}}
=== Rengdêr ===
{{rengdêr|tr}}
# [[asfaltkirî]]
#: {{mk|tr|Uzun bir '''asfalt''' yol üzerinde koştuk.|Me li ser riyeke dirêj a asfatkirî baz dan.}}
00c1a1nmhi2dqo64p42kuc66cnp6mal
-nî
0
44711
6241689
6231032
2026-07-11T22:33:01Z
Wikihez
7344
/* Paşgir */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin
6241689
wikitext
text/x-wiki
{{bnr-h|ni|nî|ni-|-nî|Ni}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Paşgir ===
{{paşgir|ku}}
# [[paşgir]]ek e ku pê hin [[rengdêr]] ji [[hoker]]an tên [[çêkirin]]
#: {{qfnim|ku|erê|erênî}}
#: {{qfnim|ku|bila|bilanî}}
#: {{qfnim|ku|neyî|neyînî}}
# [[paşgir]]ek ku hin formên duyem yên [[hoker]]an pê tên çêkirin:
#: {{qfnim|ku|heta|hetanî}}
#: {{qfnim|ku|heya|heyanî}}
#: {{qfnim|ku|mîna|mînanî}}
#: {{qfnim|ku|nola|nolanî}}
#: {{qfnim|ku|fena|fenanî}}
# {{e|ku|Reşwî|Koçgîrî|Xorasanî}} kesê yekem yê pirjimar di dema niha de
#* {{jêder|ku|jêgirtin=Min henek pere danê lê ne bi dilê min bû</br>Min çay îkramê kir</br>Gotin ecela me heye em ê dereng bimê'''nî'''|ji kovareke Bîrnebûnê, http://birnebun.eu/hejmar/birnebunweb43.pdf}}
==== Têkildar ====
* {{g|ku|-ahî}}
* {{g|ku|-anî}}
* {{g|ku|-atî}}
* {{g|ku|-ayî}}
* {{g|ku|-î}}
* {{g|ku|-îtî}}
* {{g|ku|-tî}}
==== Jê ====
{{paşgirbibîne|ku}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
[[Kategorî:Koçgîrî]]
6oh65fwcf57no9c7ath53vf5jjbifg2
qîr
0
52822
6241665
6235169
2026-07-11T20:33:05Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241665
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr 1 ===
[[Wêne:106 cunetas asfalto calle sucre (12523244613).jpg|thumb|qîr]]
{{navdêr|ku|z=m}}
# Tiştek [[reş]], [[çir]], [[ron]] û [[don]] e.
#: {{hevmaneyên peyvê|ku|qetran}}
#* {{jêder|ku|jêgirtin=(...) derkevin ser riyeke '''qîr''' û zift, hûn ê ji wir jî dakevin jêr (...)|''[[w:Dara Hinarê|Dara Hinarê]]'', [[w:Yaşar Kemal|Yaşar Kemal]], Weşanên [[w:Nûdem|Nûdem]]}}
#* {{jêder|ku|{{Jêgirtin/Ehmedê Xanî/Mem û Zîn}}|jêgirtin=Kîjek 'ereban e lêvdeqandî</br>Ser ta bi piyan reş e wekî '''qîr'''</br>Ne la'iqê behs û xwestina mîr«}}
==== Bide ber ====
* {{g|ku|asfalt}}
* {{g|ku|çîmento}}
* {{g|ku|gêç}}
* {{g|ku|seb}}
==== Jê ====
* {{g|ku|qîr kirin}}
* {{g|ku|qîrkirin}}
* {{g|ku|qîrkirî}}
* {{g|ku|qîrî}}
==== Etîmolojî ====
Ji {{ji|akk|ku|tr=qîru}}.
==== Werger ====
{{werger-ser}}
* {{Z|sq}}: {{W+|sq|katran}}
* {{Z|de}}: {{W+|de|Teer|m}}, {{W+|de|Bitumen|m|guman=erê}}
* {{Z|da}}: {{W+|da|tjære}}
* {{Z|ar}}: {{W-|ar|قَطْران|tr=qetran}}
* {{Z|eo}}: {{W-|eo|gudro}}
* {{Z|fa}}: {{W+|fa|داد}}, {{W-|fa|فریاد بلند}}, {{W-|fa|کلاغ سیاه}}, {{W+|fa|قیر}}, {{W+|fa|قیر|guman=erê}}
* {{Z|fo}}: {{W-|fo|tjøra}}
* {{Z|fi}}: {{W+|fi|terva}}
* {{Z|fr}}: {{W+|fr|goudron|m}}
* {{nl}}. [[teer]]
* {{Z|he}}: {{W+|he|זפת}}
* {{Z|ang}}: {{W-|ang|tierwe}}, {{W-|ang|teoro}}
* {{Z|en}}: {{W+|en|tar}}, {{W+|en|asphalt}}, {{W+|en|pitch}}, {{W+|en|bitumen|guman=erê}},
* {{Z|it}}: {{W+|it|catrame}}
* {{Z|is}}: {{W-|is|tjara}}
* {{Z|ca}}: {{W+|ca|quitrà|m}}
* {{Z|hu}}: {{W+|hu|kátrány}}
* {{Z|pl}}: {{W-|pl|Smoła}}
* {{Z|pt}}: {{W+|pt|alcatrão}}
* {{Z|ru}}: {{W+|ru|Дёготь}}
* {{Z|sh}}: {{W+|sh|katran|m}}
* {{Z|sh}}: {{W+|sh|katran|m}}
* {{Z|sh}}:
*: Kirîlî: [[катран]] {{m}}
*: Latînî: {{W-|la|katran|m}}
* {{Z|es}}: {{W+|es|alquitrán|m}}, {{W+|es|brea}}
* {{Z|sv}}: {{W+|sv|tjära|c}}
* {{Z|tr}}: {{W+|tr|katran}}, {{W+|tr|asfalt}}, {{W+|tr|çığlık}}, {{W+|tr|haykırı}}, {{W+|tr|nara}}, {{W+|tr|zift}}
* {{Z|vi}}: {{W+|vi|hắc ín}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# {{f|ku|reng}} wek qîrê [[reş]], [[pir]] [[reş]]
#* {{bêmînak|ku}}
# qîr[[reş]], ango [[pir]] [[reş]] e,
#: {{mk|ku|Mirîşkek qîreş li naviya gund peyda bû.}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{ku-tewîn-nav|qîr|mê}}
{{navdêr|ku|z=m}}
# [[qîrîn]], [[qîjîn]], [[hewar]], [[gazî]], [[fîxan]], [[deng]]ê [[bilind]]
#* {{bêmînak|ku}}
==== Herwiha ====
* {{g|ku|qêr}}
* {{g|ku|qêrr}}
* {{g|ku|qîrr}}
==== Jê ====
* {{g|ku|qîrrandin}}
* {{g|ku|qîrrandî}}
* {{g|ku|qîrîn}}
==== Etîmolojî ====
Ji {{ji|arc|ku|ܩܪܐ|tr=q-r-a-|w=[[gazî]] kirin, [[bang]] kirin, [[qîrîn]], bi dengê bilind [[xwandin]]}}, hevreha {{hv|he|קריאה}} (qirîa: qîrîn, xwandin), erebî {{g|ar|قرء}} (q-r-e-: [bi dengê bilind] [[xwandin]]). Ji eynî rehî: [[Qur'an]], [[qiraet]].
==== Werger ====
{{werger-ser}}
* {{Z|ar}}: {{W-|ar|القار|guman=erê}}, {{W-|ar|القیر|guman=erê}}
* {{Z|tr}}: {{W+|tr|nara}}
{{werger-bin}}
8q4pum3m3p1xeelmmw2m6ft5z35gzad
Tewandin:gotin
106
61042
6241693
6238354
2026-07-11T22:49:34Z
Mehmet1922
14058
6241693
wikitext
text/x-wiki
== Reh ==
'''Rehên dema niha''':
* Standard: -bêj-
* Devkî: -bê- (kurmanciya navendî û rojhilatî)
* Devokî:
** -vê- (kurmanciya serhedî)
** -wê- (kurmanciya rojavayî û xorasanî)
** -wegî- (Şingal) {{çp}}
== Tabloya tewandinê ==
{{etîket tewandin
|etîket1 = Standard
|naverok1 = {{ku-tewandin|gotin|form=gerguhêz|niha=bêj|borî=got |tablo=ergatîv}}
|etîket2 = Devkî: kurmanciya navendî
|naverok2 = {{ku-tewandin|gotin|form=gerguhêz|niha=bê|borî=go}}
|etîket3 = Devkî: kurmanciya rojhilatî
|naverok3 = {{ku-tewandin|gotin|form=gerguhêz|niha=bê|borî=go|devok=rojhilatî}}
|etîket4 = Kurmanciya serhedî
|naverok4 = {{ku-tewandin|gotin|form=gerguhêz|niha=vê|borî=go}}
|etîket5 = Kurmanciya rojavayî
|naverok5 = {{ku-tewandin|gotin|form=gerguhêz|niha=wê|borî=go}}
}}
ijp4zinw2qqfwtw8m7eow0j8dmypqck
Tewandin:kirin
106
61065
6241685
6237839
2026-07-11T22:26:56Z
Mehmet1922
14058
6241685
wikitext
text/x-wiki
{{etîket tewandin
|etîket1 = Standard, kurmanciya navendî, rojavayî û serhedî
|naverok1 = {{ku-tewandin|kirin|form=gerguhêz|niha=k|borî=kir |tablo=ergatîv}}
|etîket2 = Kurmanciya rojhilatî
|naverok2 = {{ku-tewandin|kirin|form=gerguhêz|niha=ke|borî=kir|devok=rojhilatî}}
}}
k2jheqptr5qlqxb0fdywn9u5jah02kr
divançe
0
132635
6241695
4609211
2026-07-11T23:17:17Z
Wikihez
7344
/* {{ziman|tr}} */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]
6241695
wikitext
text/x-wiki
== {{ziman|tr}} ==
=== Navdêr ===
{{navdêr|tr}}
# [[dîwançe]] {{îzah|dîwana biçûk a helbestan}}
q5up1mgwgnq1wjxsg8w4gyumi9g58oy
6241700
6241695
2026-07-11T23:30:46Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241700
wikitext
text/x-wiki
== {{ziman|tr}} ==
=== Navdêr ===
{{navdêr|tr}}
# {{e|tr|şiîr}} [[dîwançe]] {{îzah|dîwana biçûk a helbestan}}
sl79gqx5tg25t9c4mlgj771zxtitf9c
lenguîstîk
0
383836
6241710
6171051
2026-07-11T23:54:40Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241710
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{navdêr|ku|z=m}}
# [[zimanzanî]], [[zimannasî]], [[fîlolojî]]
==== Herwiha ====
* {{hw|ku|lînguîstîk|lingwistîk}}
==== Etîmolojî ====
Ji {{qertaf|ku|lenguîstî|-k}}.
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|زبانشناسی}}
* {{Z|tr}}: {{W+|tr|dil bilimi}}, {{W+|tr|lisaniyet}}
{{werger-bin}}
jxfbx4eh7jpyt285kvwq6zvujaoa1tp
spin
0
409494
6241644
6093698
2026-07-11T18:11:00Z
Keyomerd
8814
/* Lêker */
6241644
wikitext
text/x-wiki
== {{ziman|nl}} ==
=== Navdêr ===
{{navdêr|nl|z=m}}
# {{mijar|nl|heywan}} {{g|ku|tevnpîrk}}
=== Çavkanî ===
{{rûpela wergerê|nl|tevnpîrk}}
== {{ziman|en}} ==
=== Bilêvkirin ===
* {{deng|en|en-us-spin.ogg|dever=DYA}}
* {{deng|en|en-au-spin.ogg|dever=Awistralya}}
=== Lêker ===
{{en-tewîn-lk|form=awarte|n3y=spins|b=spun|pb=spun|pn=spinning}}
{{lêker|en}}
# {{g|ku|zîz bûn|id=spin}}
=== Navdêr ===
# {{f|en|fizîk}} [[spîn]]
fay80daw7hz0vx3zq99b4c91mn422xz
6241648
6241644
2026-07-11T18:13:53Z
Keyomerd
8814
/* Lêker */
6241648
wikitext
text/x-wiki
== {{ziman|nl}} ==
=== Navdêr ===
{{navdêr|nl|z=m}}
# {{mijar|nl|heywan}} {{g|ku|tevnpîrk}}
=== Çavkanî ===
{{rûpela wergerê|nl|tevnpîrk}}
== {{ziman|en}} ==
=== Bilêvkirin ===
* {{deng|en|en-us-spin.ogg|dever=DYA}}
* {{deng|en|en-au-spin.ogg|dever=Awistralya}}
=== Lêker ===
{{en-tewîn-lk|form=awarte|n3y=spins|b=spun|pb=spun|pn=spinning}}
{{lêker|en}}
# {{g|ku|zîz bûn|id=spin}}, [[çerixîn]]
=== Navdêr ===
# {{f|en|fizîk}} [[spîn]]
bosb83o558nfkapxkkfxdr095cgf3xb
6241649
6241648
2026-07-11T18:37:29Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241649
wikitext
text/x-wiki
== {{ziman|nl}} ==
=== Navdêr ===
{{navdêr|nl|z=m}}
# {{mijar|nl|heywan}} {{g|ku|tevnpîrk}}
=== Çavkanî ===
{{rûpela wergerê|nl|tevnpîrk}}
== {{ziman|en}} ==
=== Bilêvkirin ===
* {{deng|en|en-us-spin.ogg|dever=DYA}}
* {{deng|en|en-au-spin.ogg|dever=Awistralya}}
=== Lêker ===
{{en-tewîn-lk|form=awarte|n3y=spins|b=spun|pb=spun|pn=spinning}}
{{lêker|en}}
# {{g|ku|zîz bûn|id=spin}}, [[çerixîn]]
=== Navdêr ===
{{navdêr|en}}
# {{f|en|fizîk}} [[spîn]]
sigl0ooqby4wnfb0pu9446j4omvnacn
wîze
0
540737
6241705
6018952
2026-07-11T23:44:15Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241705
wikitext
text/x-wiki
{{bnr-h|wize}}
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku}}
# misadeya têketinê, [[destûra têketinê]]
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Einreiseerlaubnis}}
* {{Z|tr}}: {{W+|tr|vize}}
{{werger-bin}}
kok1cbtpcj44blm3gzhgbqwmieioxg0
6241706
6241705
2026-07-11T23:44:27Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241706
wikitext
text/x-wiki
{{bnr-h|wize}}
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku|c=m}}
# misadeya têketinê, [[destûra têketinê]]
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Einreiseerlaubnis}}
* {{Z|tr}}: {{W+|tr|vize}}
{{werger-bin}}
qrltr5wqnutt49zdgw5s8ax4l7j7ueb
Tewandin:dan
106
608981
6241691
5142068
2026-07-11T22:41:35Z
Mehmet1922
14058
6241691
wikitext
text/x-wiki
{{etîket tewandin
|etîket1 = Standard û kurmanciya navendî, rojavayî û serhedî
|naverok1 = {{ku-tewandin|dan|form=gerguhêz|niha=d|borî=da |tablo=ergatîv}}
|etîket2 = Kurmanciya rojhilatî
|naverok2 = {{ku-tewandin|dan|form=gerguhêz|niha=de|borî=da}}
}}
bma2ctoyfngb73pzyo2w2ruf7qm81sm
Tewandin:zanîn
106
609015
6241688
6236995
2026-07-11T22:32:34Z
Mehmet1922
14058
6241688
wikitext
text/x-wiki
== Reh ==
Dema niha: {{g|ku|-zan-}}
'''Ne-erênî:'''
* ''dema niha ya giştî û dema bêt'': '''nizan-'''
* ''dema niha ya berdewam'': '''nedizan-'''
* ''demên borî'': '''ne(-)zan-'''
== Tabloya tewandinê ==
{{ku-tewandin|zanîn|form=gerguhêz|niha=zan|borî=zanî |tablo=ergatîv}}
6pf0g5wcclv51sjz8439kwim06oduv6
Tewandin:bihîstin
106
609076
6241690
6236998
2026-07-11T22:39:37Z
Mehmet1922
14058
6241690
wikitext
text/x-wiki
== Reh ==
'''Rehên dema niha''': -bîz-, -bîs-, -bê-, -bihîz-
== Tabloya tewandinê ==
{{ku-tewandin|bihîstin|form=gerguhêz|niha=bîz|borî=bihîst |tablo=ergatîv}}
2j1qxgmqlteg9zs1x7y08ynfdnx1nkf
Tewandin:fêm kirin
106
672012
6241694
4522301
2026-07-11T23:01:52Z
Mehmet1922
14058
6241694
wikitext
text/x-wiki
{{ku-tewandin|fêm kirin |form=gerguhêz|niha=k|borî=kir|pêşgir=fêm|valahî=erê |tablo=ergatîv}}
852qa6dww4bvdv6fs84fjbbijan08mo
Tewandin:rawestandin
106
730021
6241687
4523026
2026-07-11T22:28:50Z
Mehmet1922
14058
6241687
wikitext
text/x-wiki
{{ku-tewandin|rawestandin|form=gerguhêz|niha=westîn|borî=westand|pêşgir=ra |tablo=ergatîv}}
b5zhf8nmud25xe5bbqp604up6ufupgt
Şablon:p-mane
10
843285
6241650
5094212
2026-07-11T18:56:45Z
Wikihez
7344
6241650
wikitext
text/x-wiki
<u id="p-mane"><!--
-->{{#if:{{{1|}}}|<u style="text-decoration: underline red;">{{{1|}}}</u>}}</u><sup class="plainlinks"><nowiki>[</nowiki>[[Wîkîferheng:Daxwazên peyitandinê#{{PAGENAME}}|Ji bo vê maneyê '''çavkanî''' hewce ye]]. [{{fullurl:Wîkîferheng:Daxwazên peyitandinê|action=edit§ion=new&preload=Şablon:p-wate/preload&preloadtitle=%5B%5B{{urlencode:{{FULLPAGENAME}}}}%23p-mane%7c{{urlencode:{{FULLPAGENAME}}}}%5D%5D}} (+)] ]</sup>
<includeonly>[[Kategorî:Maneyên bêçavkanî]]</includeonly><noinclude>
{{belgekirin}}
</noinclude>
dh2rr6fat37ys0jhnpkcjutvbn2b6cp
Bikarhêner:Wikihez/common.js
2
873671
6241683
6241075
2026-07-11T22:23:55Z
Wikihez
7344
6241683
javascript
text/javascript
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/loader.js&action=raw&ctype=text/javascript')
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/formatherf.js&action=raw&ctype=text/javascript')
importScript( 'Bikarhêner:Wikihez/skrîpt/js/copyTitle.js' ); // Backlink: [[Bikarhêner:Wikihez/skrîpt/js/copyTitle.js]]
// [[Bikarhêner:Wikihez/addAutoCat.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js&action=raw&ctype=text/javascript');
importScript( 'Bikarhêner:Wikihez/newentrywiz.js' ); // Backlink: [[Bikarhêner:Wikihez/newentrywiz.js]]
//[[Bikarhêner:Wikihez/skrîpt/js/VisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/VisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/CreateTranslation.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/CreateTranslation.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/defaultVisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/defaultVisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/Gadget-catfix.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/Gadget-catfix.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/wergerîne.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/wergerîne.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/getinflections.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/getinflections.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/templateScript2.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/templateScript2.js&action=raw&ctype=text/javascript');
// [[Bikarhêner:Wikihez/şablon-lêke.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/şablon-lêke.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/editor.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/editor.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/UpdateLanguageNameAndCode.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/UpdateLanguageNameAndCode.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/TranslationAdder-Data.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/TranslationAdder-Data.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/LanguageUtils.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/LanguageUtils.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-QQ.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-QQ.js&action=raw&ctype=text/javascript');
//[[:w:Bikarhêner:Wikihez/skrîpt/js/OngletPurge.js]]
mw.loader.load('//ku.wikipedia.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/OngletPurge.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/test.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/test.js&action=raw&ctype=text/javascript');
// This array of dependencies comes from [[MediaWiki:Gadgets-definition]].
// If the list of dependencies changes, copy the text after dependencies=
// for TranslationAdder and run console.log(JSON.stringify("paste dependencies here".split(/, ?/)))
// in your browser's JavaScript console. Put the resulting array as the first argument to mw.loader.using.
//[[User:Wikihez/skrîpt/js/TranslationAdder.js]]
//mw.loader.using(["ext.gadget.LegacyScriptsNewNode","mediawiki.cookie","mediawiki.util"],
//function() {
// importScript('User:Wikihez/skrîpt/js/TranslationAdder.js');
//});
mw.loader.load('https://en.wikipedia.org/w/index.php?title=User:BrandonXLF/TodoList.js&action=raw&ctype=text/javascript');
/*
// [[:w:en:MediaWiki:Gadget-edittop.js]]
mw.loader.load('//en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-edittop.js&action=raw&ctype=text/javascript');
// [[Bikarhêner:Wikihez/addAutoCat.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/addAutoCat.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Balyozbot/Gadget-CommonWikt.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Balyozbot/Gadget-CommonWikt.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/hw-ceke.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/hw-ceke.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/sort-langheaders.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/sort-langheaders.js&action=raw&ctype=text/javascript');
//[[:en:User:Conrad.Irwin/Api.js]]
mw.loader.load('//en.wiktionary.org/w/index.php?title=User:Conrad.Irwin/Api.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/etîket-çêke.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/etîket-çêke.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/tagger.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/tagger.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-CatMaker.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-CatMaker.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-defaultVisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-defaultVisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/VisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/VisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-WiktAccFormCreation.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-WiktAccFormCreation.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/XMLize.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/XMLize.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/RhymesAdder.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/RhymesAdder.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Editor.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Editor.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-aWa.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-aWa.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/FilterTranslations.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/FilterTranslations.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/custom.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/custom.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/reformat.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/reformat.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/templateScript.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/templateScript.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/translateWiki.js]] ji aliyê [[Bikarhêner:Guherto]], [[Taybet:PermanentLink/4854098#Translatewiki.net]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/translateWiki.js&action=raw&ctype=text/javascript');
// Various fixes for the trees generated by [[Module:family tree]].
$(function () {
// Show the top toggle.
$('.familytree-toptoggle').css('display', '');
// Initialize the text of the toggles.
$('.familytree').get().forEach(function (tree) {
var isCollapsed = tree.classList.contains('mw-collapsed');
var toggles = $(tree).find('.familytree-toggle');
if (toggles[0]) {
var customToggleClass = Array.prototype.filter.call(toggles[0].classList, function (className) {
return className.indexOf('mw-customtoggle-familytree') === 0;
})[0];
if (customToggleClass) {
var toggledElement = $('#' + customToggleClass.replace('mw-customtoggle', 'mw-customcollapsible'));
if (toggledElement) {
toggles.html(toggledElement.data(isCollapsed ? 'expandtext' : 'collapsetext'));
}
}
}
});
// Change the text in the custom toggles generated by [[Module:family tree]]
// when they are clicked.
$('.mw-collapsible').on('beforeExpand.mw-collapsible beforeCollapse.mw-collapsible',
function (event) {
if (this.id.indexOf('mw-customcollapsible-familytree') === 0) {
var toggle = $('.' + this.id.replace('mw-customcollapsible', 'mw-customtoggle'));
if (event.type === 'beforeExpand') {
toggle.html(this.dataset.collapsetext);
} else { // beforeCollapse
toggle.html(this.dataset.expandtext);
}
event.stopPropagation();
}
});
});
*/
mw.util.addPortletLink( mw.config.get('skin') === 'vector' ? 'p-views' : 'p-cactions', '/w/index.php?title=' + mw.config.get('wgPageName') + '&action=edit&editintro=User:Wikihez/usenec', 'nec', 'id', 'use the New Entry Creator to create a new entry', 'a', 'nextnode');
lf5euyjk555370v8lxvle0ayj76zi1e
6241692
6241683
2026-07-11T22:41:40Z
Wikihez
7344
Restored revision 6241075 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241692
javascript
text/javascript
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/loader.js&action=raw&ctype=text/javascript')
importScript( 'Bikarhêner:Wikihez/skrîpt/js/copyTitle.js' ); // Backlink: [[Bikarhêner:Wikihez/skrîpt/js/copyTitle.js]]
// [[Bikarhêner:Wikihez/addAutoCat.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js&action=raw&ctype=text/javascript');
importScript( 'Bikarhêner:Wikihez/newentrywiz.js' ); // Backlink: [[Bikarhêner:Wikihez/newentrywiz.js]]
//[[Bikarhêner:Wikihez/skrîpt/js/VisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/VisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/CreateTranslation.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/CreateTranslation.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/defaultVisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/defaultVisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/Gadget-catfix.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/Gadget-catfix.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/wergerîne.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/wergerîne.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/getinflections.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/getinflections.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/templateScript2.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/templateScript2.js&action=raw&ctype=text/javascript');
// [[Bikarhêner:Wikihez/şablon-lêke.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/şablon-lêke.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/editor.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/editor.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/UpdateLanguageNameAndCode.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/UpdateLanguageNameAndCode.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/skrîpt/js/TranslationAdder-Data.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/TranslationAdder-Data.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/LanguageUtils.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/LanguageUtils.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-QQ.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-QQ.js&action=raw&ctype=text/javascript');
//[[:w:Bikarhêner:Wikihez/skrîpt/js/OngletPurge.js]]
mw.loader.load('//ku.wikipedia.org/w/index.php?title=Bikarhêner:Wikihez/skrîpt/js/OngletPurge.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/test.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/test.js&action=raw&ctype=text/javascript');
// This array of dependencies comes from [[MediaWiki:Gadgets-definition]].
// If the list of dependencies changes, copy the text after dependencies=
// for TranslationAdder and run console.log(JSON.stringify("paste dependencies here".split(/, ?/)))
// in your browser's JavaScript console. Put the resulting array as the first argument to mw.loader.using.
//[[User:Wikihez/skrîpt/js/TranslationAdder.js]]
//mw.loader.using(["ext.gadget.LegacyScriptsNewNode","mediawiki.cookie","mediawiki.util"],
//function() {
// importScript('User:Wikihez/skrîpt/js/TranslationAdder.js');
//});
mw.loader.load('https://en.wikipedia.org/w/index.php?title=User:BrandonXLF/TodoList.js&action=raw&ctype=text/javascript');
/*
// [[:w:en:MediaWiki:Gadget-edittop.js]]
mw.loader.load('//en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-edittop.js&action=raw&ctype=text/javascript');
// [[Bikarhêner:Wikihez/addAutoCat.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/addAutoCat.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Balyozbot/Gadget-CommonWikt.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Balyozbot/Gadget-CommonWikt.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/hw-ceke.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/hw-ceke.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/sort-langheaders.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/sort-langheaders.js&action=raw&ctype=text/javascript');
//[[:en:User:Conrad.Irwin/Api.js]]
mw.loader.load('//en.wiktionary.org/w/index.php?title=User:Conrad.Irwin/Api.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/etîket-çêke.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/etîket-çêke.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/tagger.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/tagger.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-CatMaker.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-CatMaker.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-defaultVisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-defaultVisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/VisibilityToggles.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/VisibilityToggles.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-WiktAccFormCreation.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-WiktAccFormCreation.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/XMLize.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/XMLize.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/RhymesAdder.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/RhymesAdder.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Editor.js]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Editor.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/Gadget-aWa.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/Gadget-aWa.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/FilterTranslations.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/FilterTranslations.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/custom.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/custom.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/reformat.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/reformat.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/templateScript.js]]
//mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/templateScript.js&action=raw&ctype=text/javascript');
//[[Bikarhêner:Wikihez/translateWiki.js]] ji aliyê [[Bikarhêner:Guherto]], [[Taybet:PermanentLink/4854098#Translatewiki.net]]
mw.loader.load('//ku.wiktionary.org/w/index.php?title=Bikarhêner:Wikihez/translateWiki.js&action=raw&ctype=text/javascript');
// Various fixes for the trees generated by [[Module:family tree]].
$(function () {
// Show the top toggle.
$('.familytree-toptoggle').css('display', '');
// Initialize the text of the toggles.
$('.familytree').get().forEach(function (tree) {
var isCollapsed = tree.classList.contains('mw-collapsed');
var toggles = $(tree).find('.familytree-toggle');
if (toggles[0]) {
var customToggleClass = Array.prototype.filter.call(toggles[0].classList, function (className) {
return className.indexOf('mw-customtoggle-familytree') === 0;
})[0];
if (customToggleClass) {
var toggledElement = $('#' + customToggleClass.replace('mw-customtoggle', 'mw-customcollapsible'));
if (toggledElement) {
toggles.html(toggledElement.data(isCollapsed ? 'expandtext' : 'collapsetext'));
}
}
}
});
// Change the text in the custom toggles generated by [[Module:family tree]]
// when they are clicked.
$('.mw-collapsible').on('beforeExpand.mw-collapsible beforeCollapse.mw-collapsible',
function (event) {
if (this.id.indexOf('mw-customcollapsible-familytree') === 0) {
var toggle = $('.' + this.id.replace('mw-customcollapsible', 'mw-customtoggle'));
if (event.type === 'beforeExpand') {
toggle.html(this.dataset.collapsetext);
} else { // beforeCollapse
toggle.html(this.dataset.expandtext);
}
event.stopPropagation();
}
});
});
*/
mw.util.addPortletLink( mw.config.get('skin') === 'vector' ? 'p-views' : 'p-cactions', '/w/index.php?title=' + mw.config.get('wgPageName') + '&action=edit&editintro=User:Wikihez/usenec', 'nec', 'id', 'use the New Entry Creator to create a new entry', 'a', 'nextnode');
omo5stzglcv11ou8fv3gm0kh8zz0rdx
Bikarhêner:Wikihez/common.css
2
874440
6241612
6240772
2026-07-11T13:57:31Z
Wikihez
7344
6241612
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
82ei9qvmndc9ngblbs55gtezizcvgap
6241619
6241612
2026-07-11T14:32:33Z
Wikihez
7344
6241619
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
d2hteq2aayaj2mr1zeotu366nsrv3fq
6241623
6241619
2026-07-11T14:52:46Z
Wikihez
7344
6241623
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktvi-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
mfvo6cipm482zz4fu1j4ijzsbqv6786
6241625
6241623
2026-07-11T16:04:26Z
Wikihez
7344
6241625
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktvi-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktvi-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
9jtf2rmv57vb8lc27lydzrzrcr4htxn
6241626
6241625
2026-07-11T16:07:02Z
Wikihez
7344
6241626
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktvi-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktvi-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
56wz7yotposj045dgsadd01yp9c13i5
6241629
6241626
2026-07-11T16:10:17Z
Wikihez
7344
6241629
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktvi-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktvi-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
tu1u9s1n7iqia2peonakt35l564dq76
6241630
6241629
2026-07-11T16:12:10Z
Wikihez
7344
6241630
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktvi-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktvi-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
1wbg1jjeeap7913ipsayga0kf9p8vum
6241631
6241630
2026-07-11T16:16:19Z
Wikihez
7344
6241631
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktvi-start-form textarea.wiktvi-start-step-field,
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktvi-start-form textarea.wiktvi-start-narrow,
#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktvi-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktvi-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktvi-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktvi-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktvi-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktvi-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktvi-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktvi-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktvi-dfn-label-toggle,
a.wiktvi-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktvi-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktvi-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktvi-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktvi-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-tr,
.wiktvi-dfn-nimune-sub textarea.wiktvi-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktvi-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktvi-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktvi-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktvi-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktvi-section-tabs .wiktvi-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
60qozyo1nrcrrxveadbk6hudw1kfxds
6241670
6241631
2026-07-11T20:51:08Z
Wikihez
7344
6241670
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktku-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktku-dfn-label-toggle,
a.wiktku-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktku-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
h1ntti3erck52md2cny9ea9yeogqb73
6241672
6241670
2026-07-11T21:11:41Z
Wikihez
7344
6241672
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
=================================================================== */
/* Standard Input Theming using Palette */
#wiktku-start-form textarea,
#wiktku-start-form input[type="text"],
#wiktku-start-form input[type="search"],
#wiktku-start-form select {
background-color: var(--wikt-palette-white);
color: var(--wikt-palette-black);
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 2px;
padding: 4px;
}
/* Specific sizing for Etîmolojî and Bilêvkirin (Full Width) */
textarea.wiktku-pron-text,
textarea.wiktku-etym-text {
width: 100% !important;
box-sizing: border-box !important;
min-height: 100px;
margin-top: 8px;
display: block;
}
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
width: 100%; /* Ensure full width on mobile */
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
left: 0;
background: var(--wikt-palette-white);
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 100%;
max-height: 14em;
overflow-y: scroll;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
ul.wiktku-ac-results li {
padding: 8px 10px;
cursor: pointer;
font-size: 0.95em;
min-height: 2.4em;
display: flex;
align-items: center;
color: var(--wikt-palette-black);
border-bottom: 1px solid var(--wikt-palette-lightergrey);
}
ul.wiktku-ac-results li:active,
ul.wiktku-ac-results li:hover {
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
color: var(--wikt-palette-black);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-white);
color: var(--wikt-palette-black);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Mane and Nimûne textareas ── */
textarea.wiktku-dfn-mane,
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields ── */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen);
}
/* ── POS section tabs ── */
#wiktku-section-tabs .wiktku-section-tab {
padding: 6px 12px;
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 4px 4px 0 0;
background: var(--wikt-palette-dullcyan);
color: var(--wikt-palette-black);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
background: var(--wikt-palette-white);
border-bottom-color: transparent;
font-weight: bold;
}
/* General Layout spacing */
.wiktku-start-step {
margin-bottom: 20px;
padding: 10px;
border-bottom: 1px solid var(--wikt-palette-lightergrey);
}
imt0x9swdem082tmf3dszahbb0acoyv
6241673
6241672
2026-07-11T21:16:25Z
Wikihez
7344
6241673
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — complete companion styles
Mapped to MediaWiki:Gadget-Palette.css
=================================================================== */
/* ── Global Step Field Styles ── */
#wiktku-start-form textarea,
#wiktku-start-form input[type="text"],
#wiktku-start-form input[type="search"],
#wiktku-start-form select {
background-color: var(--wikt-palette-white);
color: var(--wikt-palette-black);
border: 1px solid var(--wikt-palette-lightgrey);
}
/* ── Bilêvkirin & Etîmolojî: Full Width (Requested) ── */
textarea.wiktku-pron-text,
textarea.wiktku-etym-text {
width: 100% !important;
box-sizing: border-box !important;
min-height: 5em; /* Bigger height */
margin-top: 8px;
display: block;
resize: vertical !important;
}
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
background: var(--wikt-palette-white);
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
min-height: 2.4em;
display: flex;
align-items: center;
color: var(--wikt-palette-black);
}
ul.wiktku-ac-results li:active,
ul.wiktku-ac-results li:hover {
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
color: var(--wikt-palette-black);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktku-dfn-label-toggle,
a.wiktku-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
color: var(--wikt-palette-blue); /* Use palette blue for links */
}
.wiktku-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane and Nimûne main textareas ── */
textarea.wiktku-dfn-mane,
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields ── */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen);
}
/* ── Template selector row ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
color: var(--wikt-palette-black);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
/* Mobile Adjustments */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em);
font-size: 0.85em;
}
}
0mqwd99mozvcxcjbreg5mi9l3azkqpq
6241676
6241673
2026-07-11T21:22:01Z
Wikihez
7344
Restored revision 6241670 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241676
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktku-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktku-dfn-label-toggle,
a.wiktku-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktku-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
h1ntti3erck52md2cny9ea9yeogqb73
6241678
6241676
2026-07-11T21:35:40Z
Wikihez
7344
6241678
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktku-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktku-dfn-label-toggle,
a.wiktku-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktku-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: reduce indent and make sub-fields less wide to prevent overflow */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em); /* viewport width minus margins/padding */
font-size: 0.85em;
}
}
/* ── Template selector row inside a sense block ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── Pronunciation (bilêvkirin) section ── */
.wiktku-pron-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
/* amber-1: warm parchment tint — visually links to "sound/speech" */
background: var(--wikt-palette-amber-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
width: 100%;
box-sizing: border-box;
/* amber-0: barely-there warm tint on the textarea itself */
background: var(--wikt-palette-amber-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* ── Etymology (etîmolojî) section ── */
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
/* indigo-1: cool scholarly tint — "history / word origins" feel */
background: var(--wikt-palette-indigo-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
width: 100%;
box-sizing: border-box;
/* indigo-0: barely-there cool tint */
background: var(--wikt-palette-indigo-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* Mobile: ensure both sections stay readable at narrow widths */
@media (max-width: 720px) {
.wiktku-pron-wrap textarea.wiktku-pron-text,
.wiktku-etym-wrap textarea.wiktku-etym-text {
font-size: 1em; /* don't shrink text on mobile */
height: calc(4 * 1.4em + 8px); /* 4 lines — more comfortable on small screens */
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
font-size: 1em;
min-height: 2.4em; /* match the touch-target size used elsewhere */
}
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
b4o944ziprxhdf74ktzsvkm22lox35f
6241679
6241678
2026-07-11T21:38:46Z
Wikihez
7344
6241679
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktku-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels / lazy-reveal links ── */
a.wiktku-dfn-label-toggle,
a.wiktku-dfn-lazy-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
.wiktku-dfn-lazy-links {
margin: 2px 0 4px;
line-height: 1.8;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: larger, easier-to-type fields for all dfn textareas */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
textarea.wiktku-dfn-mane,
textarea.wiktku-dfn-nimune-text {
font-size: 1em;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em);
font-size: 1em;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
}
/* ── Template selector row inside a sense block ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── Pronunciation (bilêvkirin) section ── */
.wiktku-pron-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
/* amber-1: warm parchment tint — visually links to "sound/speech" */
background: var(--wikt-palette-amber-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
width: 100%;
box-sizing: border-box;
/* amber-0: barely-there warm tint on the textarea itself */
background: var(--wikt-palette-amber-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* ── Etymology (etîmolojî) section ── */
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
/* indigo-1: cool scholarly tint — "history / word origins" feel */
background: var(--wikt-palette-indigo-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
width: 100%;
box-sizing: border-box;
/* indigo-0: barely-there cool tint */
background: var(--wikt-palette-indigo-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* Mobile: ensure both sections stay readable at narrow widths */
@media (max-width: 720px) {
.wiktku-pron-wrap textarea.wiktku-pron-text,
.wiktku-etym-wrap textarea.wiktku-etym-text {
font-size: 1em; /* don't shrink text on mobile */
height: calc(4 * 1.4em + 8px); /* 4 lines — more comfortable on small screens */
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
font-size: 1em;
min-height: 2.4em; /* match the touch-target size used elsewhere */
}
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
p8tw17k4kqhjzo4qtro89phdaqxcoq3
6241726
6241679
2026-07-12T10:06:05Z
Wikihez
7344
6241726
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktku-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels ── */
a.wiktku-dfn-label-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: larger, easier-to-type fields for all dfn textareas */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
textarea.wiktku-dfn-mane,
textarea.wiktku-dfn-nimune-text {
font-size: 1em;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em);
font-size: 1em;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
}
/* ── Template selector row inside a sense block ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── Pronunciation (bilêvkirin) section ── */
.wiktku-pron-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
/* amber-1: warm parchment tint — visually links to "sound/speech" */
background: var(--wikt-palette-amber-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
width: 100%;
box-sizing: border-box;
/* amber-0: barely-there warm tint on the textarea itself */
background: var(--wikt-palette-amber-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* ── Etymology (etîmolojî) section ── */
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
/* indigo-1: cool scholarly tint — "history / word origins" feel */
background: var(--wikt-palette-indigo-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
width: 100%;
box-sizing: border-box;
/* indigo-0: barely-there cool tint */
background: var(--wikt-palette-indigo-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* Mobile: ensure both sections stay readable at narrow widths */
@media (max-width: 720px) {
.wiktku-pron-wrap textarea.wiktku-pron-text,
.wiktku-etym-wrap textarea.wiktku-etym-text {
font-size: 1em; /* don't shrink text on mobile */
height: calc(4 * 1.4em + 8px); /* 4 lines — more comfortable on small screens */
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
font-size: 1em;
min-height: 2.4em; /* match the touch-target size used elsewhere */
}
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
94kazc7zg9lk45rgsvyc77ketgmp8d3
6241745
6241726
2026-07-12T11:44:29Z
Wikihez
7344
6241745
css
text/css
/* ===================================================================
MediaWiki:Gadget-start.js — companion styles
Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS
page) so that the JS gadget no longer needs to inject styles at runtime.
Requires MediaWiki:Gadget-Palette.css to be loaded for the
--wikt-palette-* custom properties.
=================================================================== */
/* Resizable textareas inside the wizard form */
#wiktku-start-form textarea.wiktku-start-step-field,
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield {
resize: both !important;
overflow: auto !important;
box-sizing: border-box !important;
vertical-align: top;
}
/* Narrow single-line textareas */
#wiktku-start-form textarea.wiktku-start-narrow,
#wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow {
width: 20em;
min-width: 8em;
height: calc(1em + 8px);
min-height: calc(1em + 8px);
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
}
/* ── Mobile autocomplete widget ── */
.wiktku-native-select-wrap {
display: inline-block;
position: relative;
}
.wiktku-native-select-wrap input[type="search"] {
display: block;
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
ul.wiktku-ac-results {
position: absolute;
z-index: 9999;
top: 100%;
bottom: auto;
left: 0;
/* white in light mode, near-black in dark mode */
background: var(--wikt-palette-white);
/* lightgrey border, recedes in dark mode */
border: 1px solid var(--wikt-palette-lightgrey);
margin: 0;
padding: 0;
list-style: none;
width: 20em;
max-width: 90vw;
max-height: 14em;
overflow-y: scroll; /* scroll (not auto) ensures touch-scroll works on iOS/Android */
overscroll-behavior: contain; /* prevents page scroll bleeding through */
-webkit-overflow-scrolling: touch; /* legacy iOS momentum scrolling */
}
ul.wiktku-ac-results li {
padding: 6px 10px;
cursor: pointer;
font-size: 0.95em;
/* larger touch target on mobile */
min-height: 2.4em;
display: flex;
align-items: center;
}
ul.wiktku-ac-results li:active {
/* blue-9: vivid blue in light, readable bright blue in dark */
background: var(--wikt-palette-blue-9);
color: var(--wikt-palette-white);
}
/* ── Wikitext preview panel ── */
#wiktku-preview-panel {
margin-top: 1em;
padding: 0.8em;
/* paleblue: #f8f9fa light → #1c2229 dark (matches MediaWiki's surface tones) */
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
white-space: pre-wrap;
word-break: break-word;
font-family: monospace;
font-size: 0.9em;
}
/* ── Live rendered preview panel (desktop only) ── */
#wiktku-live-preview-panel {
margin-top: 1em;
padding: 0.8em;
background: var(--wikt-palette-paleblue);
border: 1px solid var(--wikt-palette-lightgrey);
word-break: break-word;
min-height: 2em;
}
/* ── Preview container (holds wikitext + live panels) ── */
#wiktku-preview-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
margin-top: 0.5em;
}
/* ── Definition sense labels ── */
a.wiktku-dfn-label-toggle {
display: inline-block;
margin: 2px 4px 2px 0;
font-size: 0.85em;
}
/* ── Mane textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-mane {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne main textarea: full width, 2-line start height ── */
textarea.wiktku-dfn-nimune-text {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne sub-fields (transliteration + translation) ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub {
margin-top: 3px;
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
/* Both sub-textareas: same starting size, full width of the indented column */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
min-width: 8em;
padding-top: 2px !important;
padding-bottom: 2px !important;
line-height: 1.4 !important;
font-size: 0.9em;
}
/* Subtle tint to distinguish tr from t at a glance */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* Mobile: larger, easier-to-type fields for all dfn textareas */
@media (max-width: 720px) {
.wiktku-dfn-nimune-sub {
margin-left: 0.5em;
padding-left: 0.4em;
}
textarea.wiktku-dfn-mane,
textarea.wiktku-dfn-nimune-text {
font-size: 1em;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
max-width: calc(100vw - 6em);
font-size: 1em;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
}
/* ── Template selector row inside a sense block ── */
.wiktku-dfn-tpl-row {
margin-bottom: 4px;
}
.wiktku-dfn-tpl-select {
font-size: 0.9em;
}
input.wiktku-dfn-tpl-title {
width: 20em;
max-width: 100%;
box-sizing: border-box;
}
/* ── Pronunciation (bilêvkirin) section ── */
.wiktku-pron-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
/* amber-1: warm parchment tint — visually links to "sound/speech" */
background: var(--wikt-palette-amber-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
width: 100%;
box-sizing: border-box;
/* amber-0: barely-there warm tint on the textarea itself */
background: var(--wikt-palette-amber-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* ── Etymology (etîmolojî) section ── */
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
/* indigo-1: cool scholarly tint — "history / word origins" feel */
background: var(--wikt-palette-indigo-1);
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
width: 100%;
box-sizing: border-box;
/* indigo-0: barely-there cool tint */
background: var(--wikt-palette-indigo-0);
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
/* Mobile: ensure both sections stay readable at narrow widths */
@media (max-width: 720px) {
.wiktku-pron-wrap textarea.wiktku-pron-text,
.wiktku-etym-wrap textarea.wiktku-etym-text {
font-size: 1em; /* don't shrink text on mobile */
height: calc(4 * 1.4em + 8px); /* 4 lines — more comfortable on small screens */
min-height: calc(4 * 1.4em + 8px);
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
font-size: 1em;
min-height: 2.4em; /* match the touch-target size used elsewhere */
}
}
/* ── POS section tabs ── */
#wiktku-section-tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 0.6em;
}
#wiktku-section-tabs .wiktku-section-tab {
padding: 3px 10px;
/* dullcyan: #eaecf0 light → #27292d dark (MediaWiki's standard inactive tab tone) */
border: 1px solid var(--wikt-palette-lightgrey);
border-radius: 3px 3px 0 0;
background: var(--wikt-palette-dullcyan);
cursor: pointer;
font-size: 0.9em;
user-select: none;
}
#wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active {
/* white: full page background in light, deep near-black in dark */
background: var(--wikt-palette-white);
border-bottom-color: var(--wikt-palette-white);
font-weight: bold;
}
/* ── Quote / citation (jêder) block inside each nimûne item ── */
/* Toggle link — sits inline after the nimûne text/sub fields */
a.wiktku-dfn-quote-toggle {
display: inline-block;
margin-top: 4px;
font-size: 0.85em;
/* green-6: clear "add" affordance; readable in light and dark */
color: var(--wikt-palette-green-6);
}
/* The collapsible container */
.wiktku-dfn-quote-block {
margin-top: 4px;
margin-left: 1em;
padding: 6px 8px;
border-left: 3px solid var(--wikt-palette-amber-1);
background: var(--wikt-palette-amber-0);
display: flex;
flex-direction: column;
gap: 4px;
}
/* Main quote textarea */
.wiktku-dfn-quote-block textarea.wiktku-dfn-nimune-quote {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
background: var(--wikt-palette-amber-0);
}
/* Sub-fields for quote tr/t — same indented style as nimûne sub-fields */
.wiktku-dfn-quote-sub {
margin-left: 1em;
padding-left: 0.6em;
border-left: 2px solid var(--wikt-palette-lightgrey);
display: flex;
flex-direction: column;
gap: 3px;
}
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
background: var(--wikt-palette-cyan);
}
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
background: var(--wikt-palette-palegreen);
}
/* Source template selector */
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 2px;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 2px;
}
/* Each label+input row */
.wiktku-dfn-quote-src-row {
display: flex;
align-items: baseline;
gap: 4px;
flex-wrap: wrap;
}
.wiktku-dfn-quote-src-row label {
font-size: 0.85em;
white-space: nowrap;
min-width: 8em;
}
input.wiktku-dfn-quote-src-input {
flex: 1 1 12em;
max-width: 100%;
box-sizing: border-box;
}
/* Mobile: full-width quote block, slightly larger touch targets */
@media (max-width: 720px) {
.wiktku-dfn-quote-block {
margin-left: 0.3em;
}
.wiktku-dfn-quote-block textarea.wiktku-dfn-nimune-quote,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
font-size: 1em;
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
.wiktku-dfn-quote-src-row label {
min-width: 6em;
}
input.wiktku-dfn-quote-src-input {
width: 100%;
flex: 1 1 100%;
}
}
jvmdwuh0fjb0y4qa7c3652cifjum5bu
Bikarhêner:Wikihez/test.js
2
969083
6241610
6241601
2026-07-11T13:35:54Z
Wikihez
7344
6241610
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Hemû qutiyên nivîsê û textareayan di forma xebatê de dikarin
// bi kaşkirina kuncê rastê yê jêr mezin an biçûk bibin.
mw.util.addCSS(
"#wiktvi-start-form textarea.wiktvi-start-step-field," +
"#wiktvi-start-form textarea.wiktvi-start-narrow," +
"#wiktvi-start-form textarea.wiktvi-dfn-subfield {" +
" resize: both !important;" +
" overflow: auto !important;" +
" box-sizing: border-box !important;" +
" vertical-align: top;" +
"}" +
"#wiktvi-start-form textarea.wiktvi-start-narrow," +
"#wiktvi-start-form textarea.wiktvi-dfn-subfield.wiktvi-start-narrow {" +
" width: 20em;" +
" min-width: 8em;" +
" height: calc(1em + 8px);" +
" min-height: calc(1em + 8px);" +
" padding-top: 2px !important;" +
" padding-bottom: 2px !important;" +
" line-height: 1.4 !important;" +
"}" +
".wiktvi-native-select-wrap { display: inline-block; position: relative; }" +
".wiktvi-native-select-wrap input[type='search'] {" +
" display: block;" +
" width: 20em;" +
" max-width: 100%;" +
" box-sizing: border-box;" +
"}" +
"ul.wiktvi-ac-results {" +
" position: absolute;" +
" z-index: 9999;" +
" background: #fff;" +
" border: 1px solid #a2a9b1;" +
" margin: 0;" +
" padding: 0;" +
" list-style: none;" +
" width: 20em;" +
" max-width: 90vw;" +
" max-height: 14em;" +
" overflow-y: auto;" +
" -webkit-overflow-scrolling: touch;" +
"}" +
"ul.wiktvi-ac-results li {" +
" padding: 6px 10px;" +
" cursor: pointer;" +
" font-size: 0.95em;" +
"}" +
"ul.wiktvi-ac-results li:active {" +
" background: #3366cc;" +
" color: #fff;" +
"}" +
"#wiktvi-preview-panel {" +
" margin-top: 1em;" +
" padding: 0.8em;" +
" background: #f8f9fa;" +
" border: 1px solid #a2a9b1;" +
" white-space: pre-wrap;" +
" word-break: break-word;" +
" font-family: monospace;" +
" font-size: 0.9em;" +
"}" +
"a.wiktvi-dfn-label-toggle," +
"a.wiktvi-dfn-lazy-toggle {" +
" display: inline-block;" +
" margin: 2px 4px 2px 0;" +
" font-size: 0.85em;" +
"}" +
".wiktvi-dfn-lazy-links {" +
" margin: 2px 0 4px;" +
" line-height: 1.8;" +
"}" +
".wiktvi-dfn-tpl-row {" +
" margin-bottom: 4px;" +
"}" +
".wiktvi-dfn-tpl-select {" +
" font-size: 0.9em;" +
"}" +
"input.wiktvi-dfn-tpl-title {" +
" width: 20em;" +
" max-width: 100%;" +
" box-sizing: border-box;" +
"}" +
"#wiktvi-section-tabs {" +
" display: flex;" +
" flex-wrap: wrap;" +
" gap: 4px;" +
" margin-bottom: 0.6em;" +
"}" +
"#wiktvi-section-tabs .wiktvi-section-tab {" +
" padding: 3px 10px;" +
" border: 1px solid #a2a9b1;" +
" border-radius: 3px 3px 0 0;" +
" background: #eaecf0;" +
" cursor: pointer;" +
" font-size: 0.9em;" +
" user-select: none;" +
"}" +
"#wiktvi-section-tabs .wiktvi-section-tab.wiktvi-tab-active {" +
" background: #fff;" +
" border-bottom-color: #fff;" +
" font-weight: bold;" +
"}"
);
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yek hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan (ku berê hatine paqijkirin bi $.trim) vediguherîne
* beşa wikînivîsê ya di bin tarîfekê de: an rêzikên "#: {{nm|...}}"
* bo her nimûneyekê, an "#* {{bênimûne|lang}}" ger ti nimûne tinebe.
* Vê mantiqê carekê tenê hebe — di kodê ya berê de du caran hatibû
* nivîsandin (bo dema tarîf heye û ne vala ye).
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (nimune) {
return nimune !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (nimune) {
if (nimune === "") return undefined;
var bolded = nimune.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
return "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded) + "}}";
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
tplSelect.append(
$("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
);
});
// Shows only options valid for the current lang; resets selection if
// the currently chosen template is no longer valid.
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
tplSelect.find("option[value!='']").each(function () {
var allowed = $(this).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
$(this).toggle(visible);
if ($(this).val() === currentVal && visible) currentStillValid = true;
});
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — appended after the links row.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield" + (g.narrow ? " wiktvi-start-narrow" : ""));
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tpl = block.find("select.wiktvi-dfn-tpl-select").val() || "";
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
senses.push({
tpl: tpl,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readList("wiktvi-dfn-nimune"),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne is always visible.
restoreSubList("wiktvi-dfn-nimune", sense.nimune);
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit)
var livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
var livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").css({
"margin-top": "1em",
"padding": "0.8em",
"background": "#f8f9fa",
"border": "1px solid #a2a9b1",
"word-break": "break-word",
"min-height": "2em"
}).hide();
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>").css({
"display": "flex",
"flex-wrap": "wrap",
"gap": "1em",
"margin-top": "0.5em"
});
previewContainer.append(previewPanel).append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
cu7s9fdudlwa5wd9dw1kztritz7xnf1
6241611
6241610
2026-07-11T13:56:58Z
Wikihez
7344
6241611
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yek hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan (ku berê hatine paqijkirin bi $.trim) vediguherîne
* beşa wikînivîsê ya di bin tarîfekê de: an rêzikên "#: {{nm|...}}"
* bo her nimûneyekê, an "#* {{bênimûne|lang}}" ger ti nimûne tinebe.
* Vê mantiqê carekê tenê hebe — di kodê ya berê de du caran hatibû
* nivîsandin (bo dema tarîf heye û ne vala ye).
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (nimune) {
return nimune !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (nimune) {
if (nimune === "") return undefined;
var bolded = nimune.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
return "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded) + "}}";
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
tplSelect.append(
$("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "")
);
});
// Shows only options valid for the current lang; resets selection if
// the currently chosen template is no longer valid.
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
tplSelect.find("option[value!='']").each(function () {
var allowed = $(this).attr("data-langs");
// allowed="" means no restriction (show for all langs).
// .toggle() is unreliable on <option> elements in many browsers;
// use the hidden property + disabled so the option is truly invisible
// and cannot be selected programmatically when filtered out.
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
$(this).prop("hidden", !visible).prop("disabled", !visible);
if ($(this).val() === currentVal && visible) currentStillValid = true;
});
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — appended after the links row.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield" + (g.narrow ? " wiktvi-start-narrow" : ""));
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readList("wiktvi-dfn-nimune"),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne is always visible.
restoreSubList("wiktvi-dfn-nimune", sense.nimune);
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit)
var livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
var livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").css({
"margin-top": "1em",
"padding": "0.8em",
"background": "#f8f9fa",
"border": "1px solid #a2a9b1",
"word-break": "break-word",
"min-height": "2em"
}).hide();
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>").css({
"display": "flex",
"flex-wrap": "wrap",
"gap": "1em",
"margin-top": "0.5em"
});
previewContainer.append(previewPanel).append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
hfrpfaez4ys0lpcpn3aoatb2rzjnwh2
6241614
6241611
2026-07-11T14:10:03Z
Wikihez
7344
6241614
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yek hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan (ku berê hatine paqijkirin bi $.trim) vediguherîne
* beşa wikînivîsê ya di bin tarîfekê de: an rêzikên "#: {{nm|...}}"
* bo her nimûneyekê, an "#* {{bênimûne|lang}}" ger ti nimûne tinebe.
* Vê mantiqê carekê tenê hebe — di kodê ya berê de du caran hatibû
* nivîsandin (bo dema tarîf heye û ne vala ye).
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (nimune) {
return nimune !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (nimune) {
if (nimune === "") return undefined;
var bolded = nimune.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
return "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded) + "}}";
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — appended after the links row.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield" + (g.narrow ? " wiktvi-start-narrow" : ""));
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readList("wiktvi-dfn-nimune"),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne is always visible.
restoreSubList("wiktvi-dfn-nimune", sense.nimune);
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit)
var livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
var livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").css({
"margin-top": "1em",
"padding": "0.8em",
"background": "#f8f9fa",
"border": "1px solid #a2a9b1",
"word-break": "break-word",
"min-height": "2em"
}).hide();
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>").css({
"display": "flex",
"flex-wrap": "wrap",
"gap": "1em",
"margin-top": "0.5em"
});
previewContainer.append(previewPanel).append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
jblpr1fubdzk51hgq4yaqqryr7gleda
6241615
6241614
2026-07-11T14:13:35Z
Wikihez
7344
6241615
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yek hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan (ku berê hatine paqijkirin bi $.trim) vediguherîne
* beşa wikînivîsê ya di bin tarîfekê de: an rêzikên "#: {{nm|...}}"
* bo her nimûneyekê, an "#* {{bênimûne|lang}}" ger ti nimûne tinebe.
* Vê mantiqê carekê tenê hebe — di kodê ya berê de du caran hatibû
* nivîsandin (bo dema tarîf heye û ne vala ye).
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (nimune) {
return nimune !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (nimune) {
if (nimune === "") return undefined;
var bolded = nimune.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
return "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded) + "}}";
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — appended after the links row.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield" + (g.narrow ? " wiktvi-start-narrow" : ""));
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readList("wiktvi-dfn-nimune"),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne is always visible.
restoreSubList("wiktvi-dfn-nimune", sense.nimune);
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit)
var livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
var livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").css({
"margin-top": "1em",
"padding": "0.8em",
"background": "#f8f9fa",
"border": "1px solid #a2a9b1",
"word-break": "break-word",
"min-height": "2em"
}).hide();
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>").css({
"display": "flex",
"flex-wrap": "wrap",
"gap": "1em",
"margin-top": "0.5em"
});
previewContainer.append(previewPanel).append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
r21b2g56qmgqq8t7ru0gzr8fcz0tysq
6241617
6241615
2026-07-11T14:29:35Z
Wikihez
7344
6241617
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan (ku berê hatine paqijkirin bi $.trim) vediguherîne
* beşa wikînivîsê ya di bin tarîfekê de: an rêzikên "#: {{nm|...}}"
* bo her nimûneyekê, an "#* {{bênimûne|lang}}" ger ti nimûne tinebe.
* Vê mantiqê carekê tenê hebe — di kodê ya berê de du caran hatibû
* nivîsandin (bo dema tarîf heye û ne vala ye).
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (nimune) {
return nimune !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (nimune) {
if (nimune === "") return undefined;
var bolded = nimune.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
return "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded) + "}}";
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — appended after the links row.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield" + (g.narrow ? " wiktvi-start-narrow" : ""));
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readList("wiktvi-dfn-nimune"),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne is always visible.
restoreSubList("wiktvi-dfn-nimune", sense.nimune);
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").css({
"margin-top": "1em",
"padding": "0.8em",
"background": "#f8f9fa",
"border": "1px solid #a2a9b1",
"word-break": "break-word",
"min-height": "2em"
}).hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>").css({
"display": "flex",
"flex-wrap": "wrap",
"gap": "1em",
"margin-top": "0.5em"
});
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
gj5zxbkvyzmsx8fqeyaw88odb6dbaj5
6241618
6241617
2026-07-11T14:30:46Z
Wikihez
7344
6241618
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan (ku berê hatine paqijkirin bi $.trim) vediguherîne
* beşa wikînivîsê ya di bin tarîfekê de: an rêzikên "#: {{nm|...}}"
* bo her nimûneyekê, an "#* {{bênimûne|lang}}" ger ti nimûne tinebe.
* Vê mantiqê carekê tenê hebe — di kodê ya berê de du caran hatibû
* nivîsandin (bo dema tarîf heye û ne vala ye).
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (nimune) {
return nimune !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (nimune) {
if (nimune === "") return undefined;
var bolded = nimune.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
return "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded) + "}}";
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — appended after the links row.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield" + (g.narrow ? " wiktvi-start-narrow" : ""));
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readList("wiktvi-dfn-nimune"),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne is always visible.
restoreSubList("wiktvi-dfn-nimune", sense.nimune);
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
tjhp82fqveuj03o1phgna4tf03f9t3h
6241620
6241618
2026-07-11T14:44:15Z
Wikihez
7344
6241620
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercimey bo kurmancî (tenê ger ziman ne "ku" be)
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
if (n.t) tpl += "|t=" + escapeTemplateParam(n.t);
}
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
// Grow the list when the last item's main field gets content.
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
if (needsTransliteration(lang)) {
li.append(
$("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
li.append(
$("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
trTa = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
mainTa.after(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field — always after tr (or after mainTa if no tr)
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
tTa = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
li.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
2z4z81mxph28qk479vrahcqfpk0j20d
6241621
6241620
2026-07-11T14:48:21Z
Wikihez
7344
6241621
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
// Grow the list when the last item's main field gets content.
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
if (needsTransliteration(lang)) {
li.append(
$("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
li.append(
$("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
trTa = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
mainTa.after(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field — always after tr (or after mainTa if no tr)
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
tTa = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
li.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
dp3e5nai7fh7bghwf679u1hynuvjui6
6241622
6241621
2026-07-11T14:52:25Z
Wikihez
7344
6241622
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
nwjted7r7jobiwfswhvu2a0pz7rdl37
6241624
6241622
2026-07-11T16:03:18Z
Wikihez
7344
6241624
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 3)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
3b0a91ld6jfhnggzycpzro2f8sx5nsl
6241627
6241624
2026-07-11T16:07:17Z
Wikihez
7344
6241627
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
kykahcpwcs3c899lev95xmqx4eyg0o1
6241628
6241627
2026-07-11T16:10:06Z
Wikihez
7344
6241628
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
gig0hde23ydx1ec1ldk4y70ctwq2ct3
6241632
6241628
2026-07-11T16:16:32Z
Wikihez
7344
6241632
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
li.on("mousedown touchstart", function (e) {
// Use mousedown/touchstart (before blur) to register the pick.
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
lnn1xvsvsrhktyk3tjeuqdz9m8mb6h7
6241633
6241632
2026-07-11T16:19:54Z
Wikihez
7344
6241633
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
var examples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var transExamples = {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade diin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
};
var pos = values.pos ? values.pos.split("/")[0] : "";
return values.lang === "ku" ? (examples[pos] || "") : (transExamples[pos] || "");
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
input.attr("placeholder", step.example(values) || "");
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
60eaq2x9ntpepcm7p959cox543lihcf
6241634
6241633
2026-07-11T16:25:03Z
Wikihez
7344
6241634
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = values[id];
if (!words.join("").length) return "";
return "==== " + header + " ====\n" + $.map(words, function (word) {
return word ? "* {{" + templateName + "|" + values.lang + "|" +
escapeTemplateParam(word) + "}}" : undefined;
}).join("\n") + "\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
var pos = values.pos ? values.pos.split("/")[0] : "";
return (steps.dfn.posExamples && steps.dfn.posExamples[pos]) || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
var exampleText = step.example(values) || "";
input.attr("placeholder", exampleText);
// For the dfn step the mane textareas live inside sense blocks,
// not directly as .wiktvi-start-step-field children of the step div.
// Update them explicitly so all existing blocks get the right placeholder.
if (step.id === "dfn") {
stepDiv.find("textarea.wiktvi-dfn-mane").attr("placeholder", exampleText || "Mane…");
}
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
d30oszfy6dsatdjvoqhbbcbcr734h24
6241636
6241634
2026-07-11T16:28:34Z
Wikihez
7344
6241636
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "=== Bilêvkirin ===\n* {{ku-kîte}}\n\n";
}
return "";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
var pos = values.pos ? values.pos.split("/")[0] : "";
return (steps.dfn.posExamples && steps.dfn.posExamples[pos]) || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
visible: function (values) {
return false;
},
output: function (values) {
if (values.lang === "ku") {
return "==== Etîmolojî ====\n{{ji?|ku}}";
}
return "";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
var exampleText = step.example(values) || "";
input.attr("placeholder", exampleText);
// For the dfn step the mane textareas live inside sense blocks,
// not directly as .wiktvi-start-step-field children of the step div.
// Update them explicitly so all existing blocks get the right placeholder.
if (step.id === "dfn") {
stepDiv.find("textarea.wiktvi-dfn-mane").attr("placeholder", exampleText || "Mane…");
}
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
47qsteme4loll7mz11q5b7l8thz6o8a
6241637
6241636
2026-07-11T16:35:55Z
Wikihez
7344
6241637
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
visible: function (values) {
return values.lang && values.pos;
},
multiple: true,
rows: 2,
output: function (values) {
var lines = values.pron || [];
var filled = $.grep(lines, function (line) { return $.trim(line) !== ""; });
if (!filled.length) return "";
return "=== Bilêvkirin ===\n" +
$.map(filled, function (line) {
return "* " + $.trim(line);
}).join("\n") + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
var pos = values.pos ? values.pos.split("/")[0] : "";
return (steps.dfn.posExamples && steps.dfn.posExamples[pos]) || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
visible: function (values) {
return values.lang && values.pos;
},
// Template definitions for etymology templates.
etymTpls: [
{ name: "(Bêyî şablon nivîse)", val: "" },
{ name: "{{ji|…}}", val: "ji" },
{ name: "{{qertaf|…}}", val: "qertaf" },
{ name: "{{q|…}}", val: "q" },
{ name: "{{hv|…}} (hevreh)", val: "hv" },
{ name: "{{mîr|…}} (mîras)", val: "mîr" },
{ name: "{{deyn|…}} (deyn)", val: "deyn" }
],
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-row").length) return null;
var row = $("<div class='wiktvi-etym-row'></div>");
var tplSelect = $("<select class='wiktvi-etym-tpl-select wiktvi-start-narrow'></select>");
$.each(steps.etym.etymTpls, function (_, tpl) {
tplSelect.append($("<option></option>").val(tpl.val).text(tpl.name));
});
var textArea = $("<textarea class='wiktvi-start-step-field wiktvi-etym-text'></textarea>")
.attr("name", "wiktvi-etym-text-" + $.now())
.attr("rows", 2)
.attr("placeholder", "Şablonê hilbijêre yan rasterast binivîse…");
row.append(tplSelect).append($("<br>")).append(textArea);
stepDiv.append(row);
return textArea;
},
output: function (values) {
var tpl = $("#wiktvi-start-etym .wiktvi-etym-tpl-select").val() || "";
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
var content = "";
if (tpl === "ji") {
// {{ji|sourcelangcode|currentlangcode|source word|tr=transcription|t=translation}}
content = "{{ji|?|" + values.lang + "|" + escapeTemplateParam(text) + "}}";
} else if (tpl === "qertaf") {
// {{qertaf|langcode|part1|part2}}
content = "{{qertaf|" + values.lang + "|" + escapeTemplateParam(text) + "}}";
} else if (tpl === "q") {
// {{q|langcode|page title}}
content = "{{q|" + values.lang + "|" + escapeTemplateParam(text) + "}}";
} else if (tpl === "hv" || tpl === "mîr" || tpl === "deyn") {
// {{hv|langcode|…}}, {{mîr|langcode|…}}, {{deyn|langcode|…}}
content = "{{" + tpl + "|" + values.lang + "|" + escapeTemplateParam(text) + "}}";
} else {
// Free-form — user writes the full markup themselves.
content = text;
}
return "==== Etîmolojî ====\n" + content + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
var exampleText = step.example(values) || "";
input.attr("placeholder", exampleText);
// For the dfn step the mane textareas live inside sense blocks,
// not directly as .wiktvi-start-step-field children of the step div.
// Update them explicitly so all existing blocks get the right placeholder.
if (step.id === "dfn") {
stepDiv.find("textarea.wiktvi-dfn-mane").attr("placeholder", exampleText || "Mane…");
}
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
3arw6biy0oplimp849y7ldx46q5zvq5
6241639
6241637
2026-07-11T16:43:51Z
Wikihez
7344
6241639
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — selecting inserts snippet at cursor.
var sel = $("<select class='wiktvi-tpl-insert-select wiktvi-start-narrow'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
var pos = values.pos ? values.pos.split("/")[0] : "";
return (steps.dfn.posExamples && steps.dfn.posExamples[pos]) || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — selecting inserts snippet at cursor.
var sel = $("<select class='wiktvi-tpl-insert-select wiktvi-start-narrow'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
var exampleText = step.example(values) || "";
input.attr("placeholder", exampleText);
// For the dfn step the mane textareas live inside sense blocks,
// not directly as .wiktvi-start-step-field children of the step div.
// Update them explicitly so all existing blocks get the right placeholder.
if (step.id === "dfn") {
stepDiv.find("textarea.wiktvi-dfn-mane").attr("placeholder", exampleText || "Mane…");
}
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) steps.pron.pronTpls = d.pronTpls;
if (d.etymTpls) steps.etym.etymTpls = d.etymTpls;
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
n09vwen6oj3bur10yn50m8iao0o3bp2
6241640
6241639
2026-07-11T16:53:42Z
Wikihez
7344
6241640
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-pron .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
var pos = values.pos ? values.pos.split("/")[0] : "";
return (steps.dfn.posExamples && steps.dfn.posExamples[pos]) || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
$.wiktviLinkify(text, callback);
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-etym .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktvi-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.pron, steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"pron", "dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "pron") {
snap.pron = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "pron") {
// Remove existing wrap so build() recreates it (avoids guard blocking restore).
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
$("#wiktvi-start-pron .wiktvi-pron-text").val(snap.pron || "");
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
$("#wiktvi-start-etym .wiktvi-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
$.each(words, function (j, word) {
var wordItems = lastRow.find("ul.wiktvi-trans-words li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
}
});
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values.
var dfnSenses = steps.dfn.getSenses($("#wiktvi-start-dfn"));
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktvi-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
var exampleText = step.example(values) || "";
input.attr("placeholder", exampleText);
// For the dfn step the mane textareas live inside sense blocks,
// not directly as .wiktvi-start-step-field children of the step div.
// Update them explicitly so all existing blocks get the right placeholder.
if (step.id === "dfn") {
stepDiv.find("textarea.wiktvi-dfn-mane").attr("placeholder", exampleText || "Mane…");
}
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "pron") {
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
gauulk2mgfw9hnojzbnd2y3je9vfpjc
6241641
6241640
2026-07-11T17:08:17Z
Wikihez
7344
6241641
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-pron .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
var pos = values.pos ? values.pos.split("/")[0] : "";
return (steps.dfn.posExamples && steps.dfn.posExamples[pos]) || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-etym .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktvi-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row select.wiktvi-start-step-keyfield," +
"li.wiktvi-trans-row .chosen-single").end()
.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.pron, steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"pron", "dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "pron") {
snap.pron = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "pron") {
// Remove existing wrap so build() recreates it (avoids guard blocking restore).
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
$("#wiktvi-start-pron .wiktvi-pron-text").val(snap.pron || "");
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
$("#wiktvi-start-etym .wiktvi-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktvi-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktvi-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
var exampleText = step.example(values) || "";
input.attr("placeholder", exampleText);
// For the dfn step the mane textareas live inside sense blocks,
// not directly as .wiktvi-start-step-field children of the step div.
// Update them explicitly so all existing blocks get the right placeholder.
if (step.id === "dfn") {
stepDiv.find("textarea.wiktvi-dfn-mane").attr("placeholder", exampleText || "Mane…");
}
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
var label = steps.pos
? (sections[i].pos || ("Beş " + (i + 1)))
: ("Beş " + (i + 1));
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
// Update label of tab we're leaving with its pos.
var leavingPos = sections[activeSection].pos || "";
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "pron") {
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
bocsypg33fuo9q3cps1ddiy4k4kd17t
6241642
6241641
2026-07-11T17:33:32Z
Wikihez
7344
6241642
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-pron .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-etym .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktvi-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.pron, steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"pron", "dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "pron") {
snap.pron = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "pron") {
// Remove existing wrap so build() recreates it (avoids guard blocking restore).
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
$("#wiktvi-start-pron .wiktvi-pron-text").val(snap.pron || "");
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
$("#wiktvi-start-etym .wiktvi-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktvi-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktvi-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "pron") {
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
var pinnedCodes = ["ku", "zza", "ckb", "sdh", "de", "ar", "fa", "fr", "fi", "en", "sv", "tr"];
var pinnedChoices = steps.lang.choices.slice(); // copy of the initial 9
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
es8ppdu6h4v38fr1n9mmxz095ov9ful
6241652
6241642
2026-07-11T19:04:31Z
Wikihez
7344
6241652
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-pron .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-etym .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktvi-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.pron, steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"pron", "dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "pron") {
snap.pron = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "pron") {
// Remove existing wrap so build() recreates it (avoids guard blocking restore).
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
$("#wiktvi-start-pron .wiktvi-pron-text").val(snap.pron || "");
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
$("#wiktvi-start-etym .wiktvi-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktvi-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktvi-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "pron") {
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
pzy10cfd1t4i34jis2do7u7d67r6r8d
6241653
6241652
2026-07-11T19:33:29Z
Wikihez
7344
6241653
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-pron .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-etym .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktvi-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"pron", "dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "pron") {
snap.pron = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "pron") {
// Remove existing wrap so build() recreates it (avoids guard blocking restore).
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
$("#wiktvi-start-pron .wiktvi-pron-text").val(snap.pron || "");
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
$("#wiktvi-start-etym .wiktvi-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktvi-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktvi-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "pron") {
$("#wiktvi-start-pron .wiktvi-pron-wrap").remove();
steps.pron.build($("#wiktvi-start-pron"));
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
esjk0svgpui2vlzhocqbvd49bo5dz0u
6241654
6241653
2026-07-11T19:38:03Z
Wikihez
7344
6241654
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktviCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktvi-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktvi-start-narrow wiktvi-ac-input");
var resultsList = $("<ul class='wiktvi-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-pron .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-pron-wrap").length) return null;
var wrap = $("<div class='wiktvi-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-pron-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-pron .wiktvi-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktvi-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktvi-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktvi-start-step-field wiktvi-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktvi-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktvi-dfn-tpl-title wiktvi-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktvi-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktvi-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktvi-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktvi-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktvi-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktvi-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktvi-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktvi-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktvi-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktvi-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktvi-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktvi-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktvi-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktvi-dfn-subfield" + (narrow ? " wiktvi-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktvi-dfn-list").length) return null;
var list = $("<ol class='wiktvi-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktvi-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktvi-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktvi-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktvi-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktvi-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktvi-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktvi-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktvi-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktvi-dfn-herwiha"),
hevmane: readList("wiktvi-dfn-hevmane"),
dijmane: readList("wiktvi-dfn-dijmane"),
koordine: readList("wiktvi-dfn-koordine"),
jornav: readList("wiktvi-dfn-jornav"),
jernav: readList("wiktvi-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktvi-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktvi-start-etym .wiktvi-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktvi-etym-wrap").length) return null;
var wrap = $("<div class='wiktvi-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-etym-" + $.now())
.attr("class", "wiktvi-start-step-field wiktvi-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktvi-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktvi-start-dfn li.wiktvi-dfn-sense").each(function () {
if ($(this).find("select.wiktvi-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktvi-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktvi-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktvi-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktvi-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktvi-trans-list");
var isLast = row.is(list.children("li.wiktvi-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktvi-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktvi-trans-list").length) return null;
var list = $("<ul class='wiktvi-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktvi-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktvi-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktvi-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktvi-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktvi-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktvi-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktvi-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktvi-dfn-sense").last();
}
// Template selector.
block.find("select.wiktvi-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktvi-dfn-mane").hide();
block.find("input.wiktvi-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktvi-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktvi-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktvi-dfn-", "").toLowerCase();
block.find("a.wiktvi-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktvi-dfn-subfield wiktvi-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktvi-dfn-etiket": sense.etiket,
"wiktvi-dfn-herwiha": sense.herwiha,
"wiktvi-dfn-hevmane": sense.hevmane,
"wiktvi-dfn-dijmane": sense.dijmane,
"wiktvi-dfn-koordine": sense.koordine,
"wiktvi-dfn-jornav": sense.jornav,
"wiktvi-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktvi-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktvi-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktvi-dfn-nimune-li'></li>");
li.find(".wiktvi-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktvi-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktvi-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktvi-start-etym .wiktvi-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktvi-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
$("#wiktvi-start-etym .wiktvi-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktvi-trans-list");
var lastRow = list.find("li.wiktvi-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktvi-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktvi-start-" + id);
var fields = stepDiv.find(".wiktvi-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktvi-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktvi-start-step-keyfield wiktvi-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktvi-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktvi-start-" + step.id + " .wiktvi-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktvi-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktvi-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktvi-start-dfn .wiktvi-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktvi-start-dfn .wiktvi-dfn-nimune-list li.wiktvi-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktvi-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktvi-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktvi-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktvi-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktvi-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktvi-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktvi-dfn-subfield wiktvi-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktvi-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktvi-start-" + stepId).slideUp();
// $("#wiktvi-start-" + stepId + " .wiktvi-start-step-field").val("");
}
else {
var stepDiv = $("#wiktvi-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktvi-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktvi-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktvi-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktvi-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktvi-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktvi-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktvi-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktvi-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktvi-start-step",
id: "wiktvi-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktvi-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktvi-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktvi-start-step-question",
"for": "wiktvi-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktvi-start-step-field",
id: "wiktvi-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktvi-start-step-field")
.attr("id", "wiktvi-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktvi-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktvi-section-tab")
.text(tabLabel)
.toggleClass("wiktvi-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktvi-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktvi-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktvi-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktvi-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktvi-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktvi-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktvi-start-dfn");
stepDiv.find("ol.wiktvi-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktvi-start-etym .wiktvi-etym-wrap").remove();
steps.etym.build($("#wiktvi-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktvi-start-trans");
transDiv.find("ul.wiktvi-trans-list").remove();
return;
}
var stepDiv = $("#wiktvi-start-" + id);
stepDiv.find(".wiktvi-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktvi-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktvi-preview-toggle'>");
var previewLabel = $("<label for='wiktvi-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktvi-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktvi-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktvi-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktvi-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktvi-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktvi-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktvi-start-trans .wiktvi-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
60ouamomr912uxqca2orckhinht7ipf
6241669
6241654
2026-07-11T20:50:24Z
Wikihez
7344
6241669
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktku-dfn-", "").toLowerCase();
block.find("a.wiktku-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
7jpexgd435ch6lxa75c3hll2oacskc3
6241671
6241669
2026-07-11T21:11:39Z
Wikihez
7344
6241671
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text") // Ensure wiktku-pron-text is here
.attr("rows", 4) // Increased rows for better visibility
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktku-dfn-", "").toLowerCase();
block.find("a.wiktku-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
b4qn6mvsgl4x0quf5zxtsehsz0k5r5d
6241674
6241671
2026-07-11T21:20:39Z
Wikihez
7344
6241674
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text") // Ensure wiktku-pron-text is here
.attr("rows", 4) // Increased rows for better visibility
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 5)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 4)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 4)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktku-dfn-", "").toLowerCase();
block.find("a.wiktku-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 4)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 4)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
35eml7pmd9kalqlh39r4edm6sygv0bz
6241675
6241674
2026-07-11T21:21:54Z
Wikihez
7344
Restored revision 6241669 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241675
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 2)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 3)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktku-dfn-", "").toLowerCase();
block.find("a.wiktku-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 1);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
7jpexgd435ch6lxa75c3hll2oacskc3
6241677
6241675
2026-07-11T21:27:30Z
Wikihez
7344
6241677
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
function escapeTemplateParam(str) {
if (typeof str !== "string") return str;
return str.replace(/\|/g, "{{!}}").replace(/=/g, "{{=}}");
}
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + escapeTemplateParam(bolded);
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + escapeTemplateParam(n.tr);
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + escapeTemplateParam(n.t);
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
escapeTemplateParam(words[0]) + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + escapeTemplateParam(w);
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + escapeTemplateParam(values.tr);
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
escapeTemplateParam(sense.tplTitle) + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return escapeTemplateParam($.trim(part));
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.map(escapeTemplateParam).join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1].map(escapeTemplateParam);
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktku-dfn-", "").toLowerCase();
block.find("a.wiktku-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
586di65wbicqf7zp9xouw4dbic18fr4
6241680
6241677
2026-07-11T21:44:53Z
Wikihez
7344
6241680
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the group hasn't been revealed yet, click its link.
if (!groupDiv.length) {
var needle = cls.replace("wiktku-dfn-", "").toLowerCase();
block.find("a.wiktku-dfn-lazy-toggle").filter(function () {
return $(this).text().toLowerCase().indexOf(needle) !== -1;
}).trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
hx04g5brwe3dtwmqcgmtu4vup2p9ldu
6241724
6241680
2026-07-12T09:19:01Z
Wikihez
7344
6241724
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = $("<div></div>").addClass("wiktku-dfn-lazy-links");
block.append(lazyLinksDiv);
// — Sub-field groups —
// nimûne: always visible (inserted after the links row).
// etîket + herwiha/hevmane/dijmane/koordine/jornav/jernav: lazy (click-to-add).
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false, lazy: false },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, lazy: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, lazy: true }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (!g.lazy) {
// Always-visible group (Nimûne) — each item is a compound widget.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
/**
* Build one nimûne <li>: a main textarea, and — depending on
* the currently selected language — optional tr/t sub-fields.
* tr (transliteration) shown when needsTransliteration(lang)
* t (translation to ku) shown when lang !== "ku"
* The sub-fields are appended inline after the main textarea.
*/
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
// Sub-fields (tr, t) sit in an indented wrapper beneath the main textarea.
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
// Store the builder so refresh() can call it when lang changes.
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Lazy group — link lives in lazyLinksDiv; group is built on click.
var addLink = $("<a href='#'></a>")
.addClass("wiktku-dfn-lazy-toggle")
.attr("data-cls", g.cls)
.text("(+ " + g.label + ")");
addLink.on("click", function (evt) {
evt.preventDefault();
addLink.remove();
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, true);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
// Insert before Nimûne (the last fixed group) to preserve declaration order.
block.find(".wiktku-dfn-nimune-group").before(groupDiv);
firstInput.focus();
});
lazyLinksDiv.append(addLink).append(" ");
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Nimûne lines.
out += formatNimune(sense.nimune, lang);
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, nimune, herwiha …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
// If the lazy group hasn't been revealed yet, trigger its link.
// Match by data-cls attribute (reliable) instead of label text
// (which contains Kurdish characters like î that break indexOf).
if (!groupDiv.find("ol, ul").length) {
block.find("a.wiktku-dfn-lazy-toggle[data-cls='" + cls + "']").trigger("click");
groupDiv = block.find("." + cls + "-group");
}
var subList = groupDiv.find("ol, ul").first();
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
4rnhizv368ncoi8it0fc9eyv3g3j3b1
6241725
6241724
2026-07-12T10:05:40Z
Wikihez
7344
6241725
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
emqslj3nf3deyn7iw3lc7khzfgkvkkl
6241730
6241725
2026-07-12T10:15:59Z
Wikihez
7344
6241730
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.pron.pronTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
smrmmhttpsss0tcwp46ihkfg0l8zt0p
6241731
6241730
2026-07-12T10:26:41Z
Wikihez
7344
6241731
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", c: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
qdwa5xcl76eoubnfhj0xqvnwdjdthev
6241734
6241731
2026-07-12T10:33:04Z
Wikihez
7344
6241734
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
s1ska67wnfipehj65nz4gqx9ngaongx
6241735
6241734
2026-07-12T10:38:33Z
Wikihez
7344
6241735
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — options populated/refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
iv36j6nl0fm7sieurmztt033i1j7jdc
6241736
6241735
2026-07-12T10:41:00Z
Wikihez
7344
6241736
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — populated via refreshTplSelect() below.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
// Populate options now that the select is in the DOM.
steps.pron.refreshTplSelect();
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — populated via refreshTplSelect() below.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
// Populate options now that the select is in the DOM.
steps.etym.refreshTplSelect();
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
odbs28rnstm14sfz19kk2d0pax4ef5t
6241737
6241736
2026-07-12T10:44:57Z
Wikihez
7344
6241737
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
// Populate options directly here using the same filter logic.
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
// Populate options directly here.
var lang = getValues().lang || "";
$.each(steps.etym.etymTpls, function (_, tpl) {
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
5qr11us3d33q08m086qq0l0ou9fkufs
6241739
6241737
2026-07-12T10:51:58Z
Wikihez
7344
6241739
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
// Populate options directly here using the same filter logic.
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
// Populate options directly here.
var lang = getValues().lang || "";
$.each(steps.etym.etymTpls, function (_, tpl) {
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns only when language changes.
var refreshLang = values.lang || "";
if (refreshLang !== refresh._lastLang) {
refresh._lastLang = refreshLang;
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
}
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
8kwapt7ll4190juhv3tahpzg8wqww9q
6241740
6241739
2026-07-12T10:53:13Z
Wikihez
7344
6241740
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
}
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
qot6wyde5hvwqz6ymg1yb5ozbwfmab5
6241742
6241740
2026-07-12T11:17:28Z
Wikihez
7344
6241742
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
if (text.length < 200) tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (!text) return "";
return "==== Etîmolojî ====\n" + text + "\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar, steps.binereherwiha,
steps.etym, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "binereherwiha", "etym", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.etym.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
7txm5bpcwjuof23lb50fd0oe79wd2fw
6241743
6241742
2026-07-12T11:27:27Z
Wikihez
7344
6241743
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin.
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
// rêz=1 is not used for ku — definitions are shown on separate lines there.
if (text.length < 200 && lang !== "ku") tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (text) {
return "==== Etîmolojî ====\n" + text + "\n\n";
}
// No etymology entered — emit {{ji?|lang}} as a placeholder,
// but only when the entry has at least one regular mane sense
// (not a template sense like {{guharto|…}}).
var hasRegularMane = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var tpl = $(this).find("select.wiktku-dfn-tpl-select").val();
var mane = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!tpl && mane) {
hasRegularMane = true;
return false; // break
}
});
if (!hasRegularMane) return "";
return "==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar,
steps.etym, steps.binereherwiha, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "etym", "binereherwiha", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.etym.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
4rtr2svsipjrxqb2ieh30bqzq8v2kq4
6241744
6241743
2026-07-12T11:43:59Z
Wikihez
7344
6241744
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t, quote, quoteTr, quoteT,
* jêderTpl, jêderFields } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* quote — jêgirtina çavkaniyê
* quoteTr — transkrîpsiyona jêgirtinê
* quoteT — tercimeya jêgirtinê
* jêderTpl — navê şablona jêderê (jêder-kitêb/kovar/malper)
* jêderFields — { key: value, … } parametreyên şablonê
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin (ne ji bo ku).
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
// rêz=1 is not used for ku — definitions are shown on separate lines there.
if (text.length < 200 && lang !== "ku") tpl += "|rêz=1";
tpl += "}}";
// — Quote / citation block —
if (typeof n === "object" && n.quote) {
// #* quote line (bold the page name like the example line)
var boldedQ = n.quote.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var quoteLine = "\n#* " + boldedQ;
if (n.quoteTr) quoteLine += "\n#*: '''" + n.quoteTr + "'''";
if (n.quoteT) quoteLine += "\n#*: " + n.quoteT;
tpl += quoteLine;
// #** citation template line
if (n.jêderTpl) {
var cite = "\n#** {{" + n.jêderTpl + "|" + lang;
cite += "|jêgirtin=" + n.quote;
if (n.quoteTr) cite += "|tr=" + n.quoteTr;
if (n.quoteT) cite += "|tercime=" + n.quoteT;
var fields = n.jêderFields || {};
$.each(fields, function (key, val) {
if (val) cite += "|" + key + "=" + val;
});
cite += "}}";
tpl += cite;
}
}
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
// — Quote / citation block —
var quoteBlock = $("<div></div>").addClass("wiktku-dfn-quote-block").hide();
// Quote text textarea
var quoteTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote")
.attr("placeholder", "Jêgirtin…");
var quoteSubWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
if (needsTransliteration(lang)) {
quoteSubWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote-tr")
.attr("placeholder", "Transkrîpsiyona jêgirtinê…")
);
}
if (lang && lang !== "ku") {
quoteSubWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote-t")
.attr("placeholder", "Tercimeya jêgirtinê (kurmancî)…")
);
}
// Source template selector
var srcSel = $("<select></select>")
.addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
var jêderDefs = steps.dfn.jêderDefs || {};
$.each(jêderDefs, function (tplName, def) {
srcSel.append($("<option></option>").val(tplName).text(def.label));
});
// Dynamic source fields container
var srcFields = $("<div></div>").addClass("wiktku-dfn-quote-src-fields");
srcSel.on("change", function () {
srcFields.empty();
var chosen = $(this).val();
if (!chosen) return;
var def = (steps.dfn.jêderDefs || {})[chosen];
if (!def) return;
$.each(def.fields, function (_, f) {
var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row");
var lbl = $("<label></label>").text(f.label + ": ");
var inp = $("<input type='text'>")
.addClass("wiktku-dfn-quote-src-input wiktku-start-narrow")
.attr("data-field-key", f.key)
.attr("placeholder", f.label + "…");
row.append(lbl).append(inp);
srcFields.append(row);
});
});
quoteBlock.append(quoteTa);
if (quoteSubWrap.children().length) quoteBlock.append(quoteSubWrap);
quoteBlock.append(srcSel).append(srcFields);
// Toggle link
var quoteToggle = $("<a></a>")
.addClass("wiktku-dfn-quote-toggle")
.attr("href", "#")
.text("+ Jêder zêde bike");
quoteToggle.on("click", function (e) {
e.preventDefault();
if (quoteBlock.is(":hidden")) {
quoteBlock.show();
$(this).text("− Jêderê rake");
quoteTa.focus();
} else {
quoteBlock.hide();
$(this).text("+ Jêder zêde bike");
// Clear all quote fields when hidden
quoteBlock.find("textarea, input[type='text']").val("");
srcSel.val("");
srcFields.empty();
}
});
li.append(quoteToggle).append(quoteBlock);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
// Populated from MediaWiki:Gadget-start.js/data.json (jêderDefs).
jêderDefs: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t?, quote?, quoteTr?, quoteT?, jêderTpl?, jêderFields? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
// Quote / citation data — only if the block is visible and has content.
var quoteBlock = $(this).find(".wiktku-dfn-quote-block");
if (quoteBlock.is(":visible")) {
var quote = $.trim($(this).find(".wiktku-dfn-nimune-quote").val());
if (quote) {
obj.quote = quote;
var qtr = $.trim($(this).find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim($(this).find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var jêderTpl = $(this).find(".wiktku-dfn-quote-src-sel").val();
if (jêderTpl) {
obj.jêderTpl = jêderTpl;
var fields = {};
$(this).find(".wiktku-dfn-quote-src-input").each(function () {
var k = $(this).attr("data-field-key");
var v = $.trim($(this).val());
if (k && v) fields[k] = v;
});
obj.jêderFields = fields;
}
}
}
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (text) {
return "==== Etîmolojî ====\n" + text + "\n\n";
}
// No etymology entered — emit {{ji?|lang}} as a placeholder,
// but only when the entry has at least one regular mane sense
// (not a template sense like {{guharto|…}}).
var hasRegularMane = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var tpl = $(this).find("select.wiktku-dfn-tpl-select").val();
var mane = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!tpl && mane) {
hasRegularMane = true;
return false; // break
}
});
if (!hasRegularMane) return "";
return "==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar,
steps.etym, steps.binereherwiha, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "etym", "binereherwiha", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t?, quote?, … } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
// Restore quote / citation data.
if (typeof n === "object" && n.quote) {
var quoteBlock = li.find(".wiktku-dfn-quote-block");
var quoteToggle = li.find(".wiktku-dfn-quote-toggle");
quoteBlock.show();
quoteToggle.text("− Jêderê rake");
li.find(".wiktku-dfn-nimune-quote").val(n.quote);
if (n.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(n.quoteTr);
if (n.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(n.quoteT);
if (n.jêderTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(n.jêderTpl).trigger("change");
// Fill in the source field inputs after the change event renders them.
if (n.jêderFields) {
$.each(n.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
}
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.etym.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate citation template definitions for the quote widget.
if (d.jêderDefs) steps.dfn.jêderDefs = d.jêderDefs;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
l02skb2a7qjxjhwzxdth1ki5mfl9yb1
6241746
6241744
2026-07-12T11:48:34Z
Wikihez
7344
6241746
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t, quote, quoteTr, quoteT,
* jêderTpl, jêderFields } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* quote — jêgirtina çavkaniyê
* quoteTr — transkrîpsiyona jêgirtinê
* quoteT — tercimeya jêgirtinê
* jêderTpl — navê şablona jêderê (jêder-kitêb/kovar/malper)
* jêderFields — { key: value, … } parametreyên şablonê
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin (ne ji bo ku).
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
// rêz=1 is not used for ku — definitions are shown on separate lines there.
if (text.length < 200 && lang !== "ku") tpl += "|rêz=1";
tpl += "}}";
// — Quote / citation block —
if (typeof n === "object" && n.quote) {
// #* quote line (bold the page name like the example line)
var boldedQ = n.quote.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var quoteLine = "\n#* " + boldedQ;
if (n.quoteTr) quoteLine += "\n#*: '''" + n.quoteTr + "'''";
if (n.quoteT) quoteLine += "\n#*: " + n.quoteT;
tpl += quoteLine;
// #** citation template line
if (n.jêderTpl) {
var cite = "\n#** {{" + n.jêderTpl + "|" + lang;
cite += "|jêgirtin=" + n.quote;
if (n.quoteTr) cite += "|tr=" + n.quoteTr;
if (n.quoteT) cite += "|tercime=" + n.quoteT;
var fields = n.jêderFields || {};
$.each(fields, function (key, val) {
if (val) cite += "|" + key + "=" + val;
});
cite += "}}";
tpl += cite;
}
}
return tpl;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
// — Quote / citation block —
var quoteBlock = $("<div></div>").addClass("wiktku-dfn-quote-block").hide();
// Quote text textarea
var quoteTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote")
.attr("placeholder", "Jêgirtin…");
var quoteSubWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
if (needsTransliteration(lang)) {
quoteSubWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote-tr")
.attr("placeholder", "Transkrîpsiyona jêgirtinê…")
);
}
if (lang && lang !== "ku") {
quoteSubWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote-t")
.attr("placeholder", "Tercimeya jêgirtinê (kurmancî)…")
);
}
// Source template selector
var srcSel = $("<select></select>")
.addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
var jêderDefs = steps.dfn.jederDefs || {};
$.each(jêderDefs, function (tplName, def) {
srcSel.append($("<option></option>").val(tplName).text(def.label));
});
// Dynamic source fields container
var srcFields = $("<div></div>").addClass("wiktku-dfn-quote-src-fields");
srcSel.on("change", function () {
srcFields.empty();
var chosen = $(this).val();
if (!chosen) return;
var def = (steps.dfn.jederDefs || {})[chosen];
if (!def) return;
$.each(def.fields, function (_, f) {
var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row");
var lbl = $("<label></label>").text(f.label + ": ");
var inp = $("<input type='text'>")
.addClass("wiktku-dfn-quote-src-input wiktku-start-narrow")
.attr("data-field-key", f.key)
.attr("placeholder", f.label + "…");
row.append(lbl).append(inp);
srcFields.append(row);
});
});
quoteBlock.append(quoteTa);
if (quoteSubWrap.children().length) quoteBlock.append(quoteSubWrap);
quoteBlock.append(srcSel).append(srcFields);
// Toggle link
var quoteToggle = $("<a></a>")
.addClass("wiktku-dfn-quote-toggle")
.attr("href", "#")
.text("+ Jêder zêde bike");
quoteToggle.on("click", function (e) {
e.preventDefault();
if (quoteBlock.is(":hidden")) {
quoteBlock.show();
$(this).text("− Jêderê rake");
quoteTa.focus();
} else {
quoteBlock.hide();
$(this).text("+ Jêder zêde bike");
// Clear all quote fields when hidden
quoteBlock.find("textarea, input[type='text']").val("");
srcSel.val("");
srcFields.empty();
}
});
li.append(quoteToggle).append(quoteBlock);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
// Populated from MediaWiki:Gadget-start.js/data.json (jederDefs).
jederDefs: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t?, quote?, quoteTr?, quoteT?, jêderTpl?, jêderFields? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
// Quote / citation data — only if the block is visible and has content.
var quoteBlock = $(this).find(".wiktku-dfn-quote-block");
if (quoteBlock.is(":visible")) {
var quote = $.trim($(this).find(".wiktku-dfn-nimune-quote").val());
if (quote) {
obj.quote = quote;
var qtr = $.trim($(this).find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim($(this).find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var jêderTpl = $(this).find(".wiktku-dfn-quote-src-sel").val();
if (jêderTpl) {
obj.jêderTpl = jêderTpl;
var fields = {};
$(this).find(".wiktku-dfn-quote-src-input").each(function () {
var k = $(this).attr("data-field-key");
var v = $.trim($(this).val());
if (k && v) fields[k] = v;
});
obj.jêderFields = fields;
}
}
}
items.push(obj);
});
return items;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (text) {
return "==== Etîmolojî ====\n" + text + "\n\n";
}
// No etymology entered — emit {{ji?|lang}} as a placeholder,
// but only when the entry has at least one regular mane sense
// (not a template sense like {{guharto|…}}).
var hasRegularMane = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var tpl = $(this).find("select.wiktku-dfn-tpl-select").val();
var mane = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!tpl && mane) {
hasRegularMane = true;
return false; // break
}
});
if (!hasRegularMane) return "";
return "==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar,
steps.etym, steps.binereherwiha, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "etym", "binereherwiha", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t?, quote?, … } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
// Restore quote / citation data.
if (typeof n === "object" && n.quote) {
var quoteBlock = li.find(".wiktku-dfn-quote-block");
var quoteToggle = li.find(".wiktku-dfn-quote-toggle");
quoteBlock.show();
quoteToggle.text("− Jêderê rake");
li.find(".wiktku-dfn-nimune-quote").val(n.quote);
if (n.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(n.quoteTr);
if (n.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(n.quoteT);
if (n.jêderTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(n.jêderTpl).trigger("change");
// Fill in the source field inputs after the change event renders them.
if (n.jêderFields) {
$.each(n.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
}
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.etym.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate citation template definitions for the quote widget.
if (d.jederDefs) steps.dfn.jederDefs = d.jederDefs;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
hk1g2jftdl51pp6jdavv715keb3mvmu
6241752
6241746
2026-07-12T11:57:36Z
Wikihez
7344
6241752
javascript
text/javascript
// Çavkanî [[vi:MediaWiki:Gadget-start.js]]
//<nowiki>
$(function () {
var ns = mw.config.get("wgNamespaceNumber");
if (ns &&
!(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) {
return;
}
var action = mw.config.get("wgAction");
if (!(action === "edit" || action === "submit") ||
!$(".mw-newarticletext, .mw-newarticletextanon").length) {
return;
}
if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) {
return; // Do not run the script wextê WF:Bilez dişuxile
}
// Herfa ewil a kelîmeyê dike mezin. Fonksiyoneke sade li şûna
// String.prototype.wiktkuCapitalize, daku prototypeya bingehîn neyê
// gemarîkirin, û bi ewletir e (rasterast li ser rêzikên vala kar dike).
function capitalize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.substr(1);
}
// Karakterên xisûsî ên RegExp-ê direvîne, daku nivîsa dînamîk (wek navê
// rûpelê) bi ewletî bikeve nav `new RegExp(...)`.
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Nivîsek li cihê kursora texareayek dixin.
* Piştî xistinê kursor li dawiya nivîsa xistî tê danîn.
*/
function insertAtCursor(el, text) {
var start = el.selectionStart;
var end = el.selectionEnd;
var val = el.value;
el.value = val.slice(0, start) + text + val.slice(end);
var pos = start + text.length;
el.selectionStart = el.selectionEnd = pos;
}
// Karakterên ku maneyeke xisûsî di parametreyên şablonan de hene ("|" ji
// hev cuda dike, "=" dibe ku wek nav=nirx were şirovekirin) direvîne,
// daku nivîsa vekirî ya bikarhêner şablonê neşikîne.
// NOTE: escapeTemplateParam is intentionally not applied — users may freely
// include | and = to add extra template parameters themselves.
var pageName = mw.config.get("wgPageName").replace(/_/g, " ");
if (ns) pageName = pageName.replace(/.*\//, "");
var pageNameRe = escapeRegExp(pageName);
var userLang = mw.config.get("wgUserLanguage");
// Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check.
var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches;
var chosenOptions = {
width: "20em",
disable_search_threshold: 0,
placeholder_text_single: "Yekî hilbijêre",
placeholder_text_multiple: "Hilbijêre",
no_results_text: "Nehat dîtin",
enable_split_word_search: true,
search_contains: true };
/**
* On mobile, replaces chosen with a single-box autocomplete widget.
* The user sees one <input>; typing filters a results list below it.
* Selecting a result sets the hidden <select> value and fires "change"
* so the rest of the form reacts normally.
*
* The original <select> is kept hidden so all existing .val() / change
* bindings continue to work unchanged.
*/
function wrapNativeSelect(select) {
var placeholder = select.attr("data-placeholder") || "Lê bigere…";
// Hide the native select — we drive it programmatically.
select.hide();
var wrapper = $("<span class='wiktku-native-select-wrap'></span>");
var textInput = $("<input type='search' autocomplete='off'>")
.attr("placeholder", placeholder)
.addClass("wiktku-start-narrow wiktku-ac-input");
var resultsList = $("<ul class='wiktku-ac-results'></ul>").hide();
// Full option cache — rebuilt when chosen:updated fires.
var allOptions = [];
function cacheOptions() {
allOptions = [];
select.find("option").each(function () {
var v = $(this).val();
if (!v) return; // skip the empty placeholder option
allOptions.push({
value: v,
text: $(this).text(),
disabled: $(this).prop("disabled")
});
});
}
cacheOptions();
function showResults(query) {
var q = query.trim().toLowerCase();
resultsList.empty();
var matched = q
? $.grep(allOptions, function (o) {
return !o.disabled && o.text.toLowerCase().indexOf(q) !== -1;
})
: allOptions.filter(function (o) { return !o.disabled; });
if (!matched.length) {
resultsList.hide();
return;
}
$.each(matched.slice(0, 50), function (_, opt) {
var li = $("<li></li>").text(opt.text).attr("data-value", opt.value);
// Use touchend instead of touchstart so that a scroll gesture does
// not accidentally select an item. We track whether the finger moved
// between touchstart and touchend — if it did, it was a scroll.
var touchMoved = false;
li.on("touchstart", function () {
touchMoved = false;
});
li.on("touchmove", function () {
touchMoved = true;
});
li.on("touchend", function (e) {
if (touchMoved) return; // was a scroll, not a tap
e.preventDefault();
selectOption(opt.value, opt.text);
});
// Keep mousedown for desktop fallback.
li.on("mousedown", function (e) {
e.preventDefault();
selectOption(opt.value, opt.text);
});
resultsList.append(li);
});
// Position the list above or below depending on available viewport space.
var inputRect = textInput[0].getBoundingClientRect();
var viewportH = window.innerHeight;
var spaceBelow = viewportH - inputRect.bottom - 8;
var spaceAbove = inputRect.top - 8;
var maxH = Math.min(224, Math.max(spaceBelow, spaceAbove)); // 224px ≈ 14em
resultsList.css({
"max-height": maxH + "px",
"top": spaceBelow >= spaceAbove ? "100%" : "auto",
"bottom": spaceBelow >= spaceAbove ? "auto" : "100%"
});
resultsList.show();
}
function selectOption(value, text) {
textInput.val(text);
select.val(value);
resultsList.hide();
select.trigger("change");
}
textInput.on("input focus", function () {
showResults($(this).val());
});
textInput.on("blur", function () {
// Short delay so a touchstart on a result item fires first.
setTimeout(function () { resultsList.hide(); }, 200);
});
// chosen:updated → re-cache (called after ziman.json loads).
select.on("chosen:updated", function () {
cacheOptions();
// If a value is already selected, keep the display text in sync.
var cur = select.val();
if (cur) {
var match = $.grep(allOptions, function (o) { return o.value === cur; })[0];
if (match) textInput.val(match.text);
}
});
// No-op .chosen() so desktop call-sites don't need guarding.
select.chosen = function () { return select; };
wrapper.append(textInput).append(resultsList).append(select);
return wrapper;
}
var langsByCode = {};
// Populated from MediaWiki:Gadget-start.js/data.json at runtime.
var metadata = {};
function needsTransliteration(langCode) {
var meta = metadata[langCode];
if (!meta || !meta.sc) return false;
var scripts = Array.isArray(meta.sc) ? meta.sc : [meta.sc];
return scripts.length > 0 && scripts[0] !== "Latn";
}
// Kodên cinsiyetê yên di metadata.g de (li gorî peymana vê skrîptê:
// m = mê, n = nêr, nt = nêtar, mn/c = mê û nêr, y = yekjimar, p = pirjimar) bo etîketên kurmancî.
var GENDER_BASE_LABELS = { m: "mê", n: "nêr", nt: "nêtar", mn: "mê û nêr", g: "giştî", y: "yekjimar", p: "pirjimar" };
/**
* Kodeke cinsiyetê (wek "m", "n-p", "p") vediguherîne etîketeke
* kurmancî ya xwendinbar. Kodên "-p" forma pirjimar a wê cinsiyetê
* nîşan didin. Kodên nenas (wek yên taybet ên hin zimanan) bi kodê
* xwe re têne nîşandan, ne bi texmînek çewt.
*/
function genderLabel(code) {
if (code === "p") return "Pirjimar";
var pluralMatch = code.match(/^(.+)-p$/);
if (pluralMatch && GENDER_BASE_LABELS[pluralMatch[1]]) {
return GENDER_BASE_LABELS[pluralMatch[1]] + " (pirjimar)";
}
return GENDER_BASE_LABELS[code] || code;
}
/**
* Rêzeke nimûneyan vediguherîne beşa wikînivîsê ya di bin tarîfekê de.
* Her nimûne dikare xwedan { text, tr, t } be:
* text — metnê nimûneyê
* tr — transkrîpsiyon (tenê ger ziman hewceyî transliterasyonê be)
* t — tercime bo kurmancî (parametreya sêyem a şablonê, bê nav)
* Ger nimûne ji 200 tîpan kêmtir be |rêz=1 tê zêdekirin (ne ji bo ku).
* Ger ti nimûne tinebe {{bênimûne|lang}} tê nivîsandin.
*/
function formatNimune(nimunes, lang) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return "\n#* {{bênimûne|" + lang + "}}";
}
return $.map(nimunes, function (n) {
var text = typeof n === "object" ? n.text : n;
if (!text) return undefined;
var bolded = text.replace(
new RegExp("(" + pageNameRe + "([^( |,|;|\\?|\\.|\\!)]+)?)", "ig"),
"'''$1'''");
var tpl = "\n#: {{nm|" + lang + "|" + bolded;
if (typeof n === "object") {
if (n.tr) tpl += "|tr=" + n.tr;
// Translation as third positional param (no key needed).
if (n.t) tpl += "|" + n.t;
}
// Short examples fit on one line together with their translation.
// rêz=1 is not used for ku — definitions are shown on separate lines there.
if (text.length < 200 && lang !== "ku") tpl += "|rêz=1";
tpl += "}}";
return tpl;
}).join("");
}
/**
* Formats a jêder (quote/citation) object into wikitext lines.
* Returns empty string when no quote is present.
* Output:
* #* <quote>
* #*: '''<quoteTr>''' (if transliteration present)
* #*: <quoteT> (if translation present)
* #** {{jêder-…|lang|jêgirtin=…|…fields…}}
*/
function formatJeder(jeder, lang) {
if (!jeder || !jeder.quote) return "";
var out = "\n#* " + jeder.quote;
if (jeder.quoteTr) out += "\n#*: '''" + jeder.quoteTr + "'''";
if (jeder.quoteT) out += "\n#*: " + jeder.quoteT;
if (jeder.jêderTpl) {
var cite = "\n#** {{" + jeder.jêderTpl + "|" + lang;
cite += "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) cite += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) cite += "|tercime=" + jeder.quoteT;
$.each(jeder.jêderFields || {}, function (key, val) {
if (val) cite += "|" + key + "=" + val;
});
cite += "}}";
out += cite;
}
return out;
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên hevşibin: jê, têkildar, binêre herwiha. Berê pênc caran bi hemû wek hev dihatin
* nivîsandin; niha cudahiya wan tenê nav, pirs û sernivîsa wan e.
*/
function makeWordListStep(id, name, question_fmt, header, templateName) {
return {
id: id,
name: name,
question_fmt: question_fmt,
multiple: true,
narrow: true,
visible: function (values) {
return values.lang && values.pos;
},
output: function (values) {
var words = $.grep(values[id] || [], function (w) { return !!w; });
if (!words.length) return "";
var lang = values.lang;
var section = "==== " + header + " ====\n";
if (words.length === 1) {
// Single word — keep the simple inline template.
return section +
"* {{" + templateName + "|" + lang + "|" +
words[0] + "}}\n\n";
}
// Multiple words — use {{kol3}} with one positional param per word.
var params = "|sernav=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\n}}\n\n";
} };
}
var steps = {
lang: {
id: "lang",
required: true,
name: "ziman",
question_fmt: "“{{PAGENAME}}” bi çi zimanî ye?",
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (langChoices).
choices: [],
output: function (values) {
return "== {{ziman|" + values.lang + "}} ==\n\n";
} },
pron: {
id: "pron",
name: "bilêvkirin",
question_fmt: "“{{PAGENAME}}” çawa tê telafûzkirin?",
// pronTpls populated from data.json
pronTpls: [],
visible: function (values) {
return !!values.lang;
},
/** Fills (or refills) the insert-dropdown from the current pronTpls array, filtering by language. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-pron .wiktku-tpl-insert-select");
if (!sel.length) return;
var lang = getValues().lang || "";
sel.find("option[value!='']").remove();
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-pron-wrap").length) return null;
var wrap = $("<div class='wiktku-pron-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-pron-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-pron-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|peyn}}");
// Template insert dropdown — filtered by language.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
var lang = getValues().lang || "";
$.each(steps.pron.pronTpls, function (_, tpl) {
// Filter: if tpl.langs exists, only show if lang is in that list; otherwise show always
var allowed = !tpl.langs || tpl.langs.indexOf(lang) !== -1;
if (allowed) {
sel.append($("<option></option>")
.val(tpl.snippet)
.text(tpl.name + " — " + tpl.desc)
.attr("data-nolang", tpl.noLang ? "1" : ""));
}
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
// Check if the selected option has noLang flag
var selectedOption = sel.find("option:selected");
var hasNoLang = selectedOption.attr("data-nolang") === "1";
if (!hasNoLang) {
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
}
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-pron .wiktku-pron-text").val());
if (!text) return "";
var lines = text.split("\n");
var out = $.map(lines, function (line) {
line = $.trim(line);
if (!line) return undefined;
return line.charAt(0) === "*" ? line : "* " + line;
}).join("\n");
return "=== Bilêvkirin ===\n" + out + "\n\n";
} },
pos: {
id: "pos",
required: true,
name: "Cureyê rêzimanî",
question_fmt: "Cureyê rêzimanî yê “{{PAGENAME}}” çi ye?",
visible: function (values) {
return values.lang;
},
question_br: true,
// Populated from MediaWiki:Gadget-start.js/data.json (posChoices).
choices: [],
output: function (values) {
var pos = values.pos || "";
var cinsiyet = values.cinsiyet || ""; // from the cinsiyet step
var lekTur = values.lektur || ""; // from the lêker transitivity step
var capitalizedPos = capitalize(pos);
var outputString = "=== " + capitalizedPos + " ===\n";
// Gender-to-Kurmancî name map (used by ku-tewîn-nav).
// "nt" tê de nîne bi qesd — ne bi "mn" tê wekhevkirin (li gorî
// biryara berê), loma ji bo "nt" şablona ku-tewîn-nav nayê zêdekirin.
var genderNames = { m: "mê", n: "nêr", mn: "mê û nêr" };
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && genderNames[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + genderNames[cinsiyet] + "}}\n";
}
outputString += "{{" + pos + "|" + values.lang;
if (pos === "navdêr" || pos === "serenav") {
if (cinsiyet) {
outputString += "|c=" + cinsiyet;
} else if (values.lang === "ku") {
// Unknown gender — prompt editor to fill it in.
outputString += "|c=?";
}
} else if (/^lêker/.test(pos) && lekTur) {
outputString += "|c=" + lekTur;
}
if (values.tr) {
outputString += "|tr=" + values.tr;
}
outputString += "}}\n";
return outputString;
}
},
/**
* cinsiyet (grammatical gender) — only shown for navdêr/serenav, û
* tenê ger metadata ji bo zimanê hilbijartî lîsteyeke "g" (cinsiyet)
* were dayîn. Bijardeyên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku ne hemû ziman heman cinsiyetan hene (an qet
* cinsiyet nînin).
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: "Cinsiyeta kelîmeyê çi ye?",
question_br: true,
visible: function (values) {
var meta = metadata[values.lang];
return !!(values.lang && (values.pos === "navdêr" || values.pos === "serenav") &&
meta && meta.g && meta.g.length);
},
build: function (stepDiv, values) {
var select = stepDiv.find("select.wiktku-start-step-field");
if (!select.length) {
select = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-cinsiyet-field" }));
stepDiv.append(select);
}
// Gava yekem (ji build()-a giştî) values nayê şandin — hîna
// ziman nehatiye hilbijartin, ji ber vê tenê select-a vala
// vegerîne, dê bi refresh() were dagirtin.
if (!values) return select;
var meta = metadata[values.lang];
var codes = (meta && meta.g) || [];
var prevVal = select.val();
var choices = $.map(codes, function (code) {
return [[code, genderLabel(code)]];
});
populateMenus(select, choices);
if ($.grep(choices, function (c) { return c[0] === prevVal; }).length) {
select.val(prevVal);
}
if (!isMobile) select.trigger("chosen:updated");
return select;
},
output: function () { return ""; } // consumed by pos.output
},
/**
* Lêker transitivity — only shown for any lêker variant.
* Add new transitivity values to the choices dict here.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê",
question_fmt: "Cureyê lêkerê çi ye?",
question_br: true,
visible: function (values) {
return values.lang && values.pos && /^lêker/.test(values.pos);
},
// Dictionary: value → display label. Add new types here.
choices: [
["gh", "Gerguhêz"],
['x-gh', 'Xwerû-gerguhêz'],
['p-gh', 'pêkhatî-gerguhêz'],
['h-gh', 'hevedudanî-gerguhêz'],
['b-gh', 'biwêjî-gerguhêz'],
["ngh", "Negerguhêz"],
['x-ngh', 'xwerû-negerguhêz'],
['p-ngh', 'pêkhatî-negerguhêz'],
['h-ngh', 'hevedudanî-negerguhêz'],
['b-ngh', 'biwêjî-negerguhêz'] ],
output: function () { return ""; } // consumed by pos.output
},
tr: {
id: "tr",
name: "transkrîpsiyon",
question_fmt: "Transkrîpsiyona kelîmeyê",
multiple: false,
narrow: true,
visible: function (values) {
return values.lang && values.pos && needsTransliteration(values.lang);
} },
dfn: {
id: "dfn",
// required: true, ger mane tinebe [[Şablon:mane?]] bi kar bîne
name: "Mane",
question_fmt: "Mane û nimûneyên kelîmeyê binivîse. Ji bo tercimeyan beşa 'Werger' bi kar bîne!",
multiple: true,
ordered: true,
rows: 3,
visible: function (values) {
return values.lang && values.pos;
},
example: function (values) {
// posExamples loaded from MediaWiki:Gadget-start.js/data.json.
// Keys may be the exact chosen pos value (e.g. "lêker/gh"), or
// just its base form before the "/" (e.g. "lêker") for pos
// values shared across variants — try the exact value first,
// then fall back to the base form.
var examples = steps.dfn.posExamples || {};
var full = values.pos || "";
var base = full.split("/")[0];
return examples[full] || examples[base] || "";
},
/**
* Builds one sense block (<li>) inside the ordered list.
* Each block contains:
* - a textarea for the definition
* - an expandable nimûne list
* - single-row sub-lists for herwiha, hevmane, dijmane
*/
buildSenseBlock: function (stepDiv) {
var block = $("<li class='wiktku-dfn-sense'></li>");
// — Mane textarea (declared first so the template handler can reference it) —
var dfnArea = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-mane-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", "wiktku-start-step-field wiktku-dfn-mane")
.attr("rows", 6)
.attr("placeholder", "Mane…");
dfnArea.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
// — Template selector (optional — replaces mane when chosen) —
// Template definitions loaded from MediaWiki:Gadget-start.js/data.json.
var tplDefs = steps.dfn.tplDefs || [];
// Cache of all non-placeholder option elements — used by updateTplOptions
// to remove/re-add options (the only approach compatible with Chosen.js).
var _allTplOptions = [];
var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" }));
tplSelect.append($("<option value=''>— an şablonek hilbijêre —</option>"));
$.each(tplDefs, function (_, tpl) {
var opt = $("<option></option>")
.val(tpl.name)
.text(tpl.name)
.attr("data-langs", tpl.langs ? tpl.langs.join(",") : "")
.attr("data-nolang", tpl.noLang ? "1" : "");
tplSelect.append(opt);
_allTplOptions.push(opt[0]);
});
function updateTplOptions() {
var lang = getValues().lang || "";
var currentVal = tplSelect.val();
var currentStillValid = false;
// Detach all non-placeholder options, then re-attach only the visible ones.
// This is the only approach that works correctly with both native <select>
// and Chosen.js on desktop.
tplSelect.find("option[value!='']").detach();
$.each(_allTplOptions, function (_, opt) {
var allowed = $(opt).attr("data-langs");
var visible = !allowed || allowed.split(",").indexOf(lang) !== -1;
if (visible) {
tplSelect.append(opt);
if ($(opt).val() === currentVal) currentStillValid = true;
}
});
if (!isMobile) tplSelect.trigger("chosen:updated");
if (currentVal && !currentStillValid) {
tplSelect.val("");
dfnArea.show();
tplTitleInput.hide().val("");
}
}
// Store updater on the element so refresh() can call it for all blocks.
tplSelect.data("updateOptions", updateTplOptions);
var tplTitleInput = $("<input type='text'>")
.addClass("wiktku-dfn-tpl-title wiktku-start-narrow")
.attr("placeholder", "Navê rûpelê…")
.hide();
// Grow the sense list when the title field of the last block gets content,
// mirroring what onDfnInput does for the plain mane textarea.
tplTitleInput.on("input", function () {
steps.dfn.onDfnInput(stepDiv, block, this);
});
tplSelect.on("change", function () {
var chosen = $(this).val();
if (chosen) {
dfnArea.hide();
tplTitleInput.show().focus();
} else {
dfnArea.show();
tplTitleInput.hide().val("");
}
// Re-run refresh so the Werger step visibility updates.
refresh();
});
var tplRow = $("<div></div>").addClass("wiktku-dfn-tpl-row")
.append(tplSelect).append(" ").append(tplTitleInput);
block.append(tplRow);
block.append(dfnArea);
// Apply lang filter on initial build.
updateTplOptions();
// — Inline links row: (+ Etîket) + all lazy sub-group triggers —
// Sits right before the Nimûne textarea; all lazy fields are revealed by clicking their link.
var lazyLinksDiv = null; // no longer used — all groups are always visible
// — Sub-field groups —
// All groups are always visible with a placeholder textarea.
// Nimûne is last in the DOM and last in the output.
var allGroups = [
{ cls: "wiktku-dfn-etiket", label: "Etîket", rows: 1, narrow: true },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true },
{ cls: "wiktku-dfn-nimune", label: "Nimûne", rows: 2, narrow: false }
];
$.each(allGroups, function (_, g) {
var groupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup " + g.cls + "-group");
if (g.cls === "wiktku-dfn-nimune") {
// Nimûne — compound widget with tr/t sub-fields.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
function buildNimuneLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-nimune-li");
var mainTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-text-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-text")
.attr("placeholder", "Nimûne…");
mainTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(list.children("li:last-child"));
if (val && isLast) {
list.append(buildNimuneLi());
}
});
li.append(mainTa);
var subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
if (needsTransliteration(lang)) {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…")
);
}
if (lang && lang !== "ku") {
subWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
groupDiv.data("buildNimuneLi", buildNimuneLi);
list.append(buildNimuneLi());
groupDiv.append(lbl).append(list);
block.append(groupDiv);
} else {
// Regular always-visible group — label + growing textarea list.
var lbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text(g.label + ": ");
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
var firstInput = $("<textarea></textarea>")
.attr("name", g.cls + "-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", g.rows)
.attr("class", "wiktku-dfn-subfield" + (g.narrow ? " wiktku-start-narrow" : ""))
.attr("placeholder", g.label + "…");
firstInput.on("input", function () {
steps.dfn.onSubInput(list, this, g.rows, g.narrow);
});
list.append($("<li></li>").append(firstInput));
groupDiv.append(lbl).append(list);
block.append(groupDiv);
}
});
// — Jêder (quote / citation) group — always visible, sibling to Nimûne —
(function () {
var lang = getValues().lang || "";
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
// Quote text textarea
var quoteTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote")
.attr("placeholder", "Jêgirtin…");
// tr/t sub-fields for the quote
var quoteSubWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
if (needsTransliteration(lang)) {
quoteSubWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote-tr")
.attr("placeholder", "Transkrîpsiyona jêgirtinê…")
);
}
if (lang && lang !== "ku") {
quoteSubWrap.append(
$("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-quote-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 2)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-quote-t")
.attr("placeholder", "Tercimeya jêgirtinê (kurmancî)…")
);
}
// Source template selector
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
var jederDefs = steps.dfn.jederDefs || {};
$.each(jederDefs, function (tplName, def) {
srcSel.append($("<option></option>").val(tplName).text(def.label));
});
// Dynamic source fields container
var srcFields = $("<div></div>").addClass("wiktku-dfn-quote-src-fields");
srcSel.on("change", function () {
srcFields.empty();
var chosen = $(this).val();
if (!chosen) return;
var def = (steps.dfn.jederDefs || {})[chosen];
if (!def) return;
$.each(def.fields, function (_, f) {
var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row");
var fieldLbl = $("<label></label>").text(f.label + ": ");
var inp = $("<input type='text'>")
.addClass("wiktku-dfn-quote-src-input wiktku-start-narrow")
.attr("data-field-key", f.key)
.attr("placeholder", f.label + "…");
row.append(fieldLbl).append(inp);
srcFields.append(row);
});
});
jederGroupDiv.append(jederLbl).append(quoteTa);
if (quoteSubWrap.children().length) jederGroupDiv.append(quoteSubWrap);
jederGroupDiv.append(srcSel).append(srcFields);
block.append(jederGroupDiv);
}());
return block;
},
/** Grows the sense list when the last mane textarea gets content. */
onDfnInput: function (stepDiv, block, textarea) {
var val = $.trim($(textarea).val());
var list = stepDiv.find("ol.wiktku-dfn-list");
var isLast = block.is(list.children("li:last-child"));
if (val && isLast) {
var newBlock = steps.dfn.buildSenseBlock(stepDiv);
list.append(newBlock);
// Apply Chosen to the new block's template selector on desktop.
if (!isMobile) newBlock.find("select.wiktku-dfn-tpl-select").chosen(chosenOptions);
}
refresh();
},
/** Grows a sub-list (nimûne/herwiha/hevmane/dijmane/termên koordîne) on input. */
onSubInput: function (list, input, rows, narrow) {
var val = $.trim($(input).val());
var item = $(input).parent();
var isLast = item.is(list.children("li:last-child"));
if (val && isLast) {
var next = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-sub-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", rows)
.attr("class", "wiktku-dfn-subfield" + (narrow ? " wiktku-start-narrow" : ""));
next.on("input", function () {
steps.dfn.onSubInput(list, this, rows, narrow);
});
list.append($("<li></li>").append(next));
}
},
// Populated from MediaWiki:Gadget-start.js/data.json (tplDefs).
tplDefs: [],
// Populated from MediaWiki:Gadget-start.js/data.json (posExamples).
posExamples: {},
// Populated from MediaWiki:Gadget-start.js/data.json (jederDefs).
jederDefs: {},
build: function (stepDiv) {
// Guard: only build once — refresh() calls build() on every
// unrelated change, so skip if the list is already present.
if (stepDiv.find("ol.wiktku-dfn-list").length) return null;
var list = $("<ol class='wiktku-dfn-list'></ol>");
list.append(steps.dfn.buildSenseBlock(stepDiv));
stepDiv.append(list);
return null;
},
/** Reads all sense blocks from the DOM and returns an array of sense objects. */
getSenses: function (stepDiv) {
var senses = [];
stepDiv.find("li.wiktku-dfn-sense").each(function () {
var block = $(this);
var tplSel = block.find("select.wiktku-dfn-tpl-select");
var tpl = tplSel.val() || "";
// noLang: template already encodes the language — don't add |lang| param.
var tplNoLang = tpl
? tplSel.find("option[value='" + tpl + "']").attr("data-nolang") === "1"
: false;
var tplTitle = $.trim(block.find("input.wiktku-dfn-tpl-title").val());
var mane = $.trim(block.find("textarea.wiktku-dfn-mane").val());
var etiket = (function () {
var vals = [];
block.find(".wiktku-dfn-etiket-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}());
function readList(cls) {
var vals = [];
block.find("." + cls + "-list textarea").each(function () {
var v = $.trim($(this).val());
if (v) vals.push(v);
});
return vals;
}
// Nimûne items are compound: { text, tr?, t? }
function readNimuneList() {
var items = [];
block.find(".wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var text = $.trim($(this).find(".wiktku-dfn-nimune-text").val());
if (!text) return;
var obj = { text: text };
var tr = $.trim($(this).find(".wiktku-dfn-nimune-tr").val());
var t = $.trim($(this).find(".wiktku-dfn-nimune-t").val());
if (tr) obj.tr = tr;
if (t) obj.t = t;
items.push(obj);
});
return items;
}
// Quote / citation data lives at the sense-block level (not per nimune item).
function readJeder() {
var jederGroup = block.find(".wiktku-dfn-jeder-group");
var quote = $.trim(jederGroup.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return null;
var obj = { quote: quote };
var qtr = $.trim(jederGroup.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(jederGroup.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = jederGroup.find(".wiktku-dfn-quote-src-sel").val();
if (tplName) {
obj.jêderTpl = tplName;
var fields = {};
jederGroup.find(".wiktku-dfn-quote-src-input").each(function () {
var k = $(this).attr("data-field-key");
var v = $.trim($(this).val());
if (k && v) fields[k] = v;
});
obj.jêderFields = fields;
}
return obj;
}
senses.push({
tpl: tpl,
tplNoLang: tplNoLang,
tplTitle: tplTitle,
mane: mane,
etiket: etiket,
nimune: readNimuneList(),
jeder: readJeder(),
herwiha: readList("wiktku-dfn-herwiha"),
hevmane: readList("wiktku-dfn-hevmane"),
dijmane: readList("wiktku-dfn-dijmane"),
koordine: readList("wiktku-dfn-koordine"),
jornav: readList("wiktku-dfn-jornav"),
jernav: readList("wiktku-dfn-jernav")
});
});
return senses;
},
getOutput: function (values, callback) {
var stepDiv = $("#wiktku-start-dfn");
var senses = steps.dfn.getSenses(stepDiv);
var lang = values.lang;
// A sense counts as "filled" if it has either a mane or a chosen template + title.
var hasMane = senses.some(function (s) {
return s.mane !== "" || (s.tpl && s.tplTitle);
});
// True only when at least one sense has a regular mane (needs linkify).
var hasRegularMane = senses.some(function (s) {
return !s.tpl && s.mane !== "";
});
var text = $.map(senses, function (sense) {
// — Template sense (e.g. {{Guharto|ku|somepage}} or {{ku-Latn|somepage}}) —
if (sense.tpl) {
if (!sense.tplTitle) return undefined;
// noLang templates encode the language in their name — omit the |lang| param.
if (sense.tplNoLang) {
return "# {{" + sense.tpl + "|" +
sense.tplTitle + "}}";
}
return "# {{" + sense.tpl + "|" + lang + "|" +
sense.tplTitle + "}}";
}
// — Normal mane sense —
var dfn = sense.mane;
if (!dfn) return undefined;
// Capitalize and punctuate.
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
// {{e|lang|label1|label2}}
var labelTpl = "";
if (sense.etiket && sense.etiket.length) {
var labelParts = sense.etiket.map(function (part) {
return $.trim(part);
}).filter(function (part) { return part !== ""; });
if (labelParts.length) {
labelTpl = " {{e|" + lang + "|" + labelParts.join("|") + "}} ";
}
}
var out = "#" + (labelTpl ? labelTpl : " ") + dfn;
// Per-sense word lists as #: template lines.
function wordLine(tpl, words) {
if (!words.length) return "";
return "\n#: {{" + tpl + "|" + lang + "|" +
words.join("|") + "}}";
}
out += wordLine("herwiha-rêz", sense.herwiha);
out += wordLine("hevmane", sense.hevmane);
out += wordLine("dijmane", sense.dijmane);
out += wordLine("termên koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last.
out += formatNimune(sense.nimune, lang);
// Jêder (quote/citation) — after nimune.
out += formatJeder(sense.jeder, lang);
return out;
}).join("\n") + "\n\n";
if (!hasMane) {
// No definitions entered — emit {{mane?}} with bênimûne.
text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n\n";
callback(text);
return;
}
if (!hasRegularMane) {
// All filled senses are template senses — no linkify needed.
callback(text);
return;
}
var didTryToLoad = function () {
// If the module failed to load, $.wiktviLinkify won't exist —
// fall back to the unlinkified text instead of throwing.
if (typeof $.wiktviLinkify === "function") {
$.wiktviLinkify(text, callback);
} else {
callback(text);
}
};
mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad);
}
},
je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê", "g"),
tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên têkildarî vê kelîmeyê binivîse", "Têkildar", "g"),
binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha", "g"),
etym: {
id: "etym",
name: "etîmolojî",
question_fmt: "Etîmolojiya kelîmeyê binivîse",
// etymTpls populated from data.json
etymTpls: [],
visible: function (values) {
return values.lang && values.pos;
},
/** Fills (or refills) the insert-dropdown from the current etymTpls array. */
refreshTplSelect: function () {
var sel = $("#wiktku-start-etym .wiktku-tpl-insert-select");
if (!sel.length) return;
sel.find("option[value!='']").remove();
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
// Notify Chosen that the option list has changed (no-op on mobile).
if (!isMobile) sel.trigger("chosen:updated");
},
build: function (stepDiv) {
if (stepDiv.find(".wiktku-etym-wrap").length) return null;
var wrap = $("<div class='wiktku-etym-wrap'></div>");
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-etym-" + $.now())
.attr("class", "wiktku-start-step-field wiktku-etym-text")
.attr("rows", 4)
.attr("placeholder", "Mînak: {{ji|en|ku|apple}} yan rasterast binivîse…");
// Template insert dropdown — options also refreshed after data.json loads.
var sel = $("<select class='wiktku-tpl-insert-select'></select>");
sel.append($("<option value=''>— şablonek lê zêde bike —</option>"));
$.each(steps.etym.etymTpls, function (_, tpl) {
sel.append($("<option></option>").val(tpl.snippet).text(tpl.name + " — " + tpl.desc));
});
sel.on("change", function () {
var snippet = $(this).val();
if (!snippet) return;
var lang = getValues().lang || "";
snippet = snippet.replace(/LANG/g, lang).replace(/SOURCELANG/g, "?");
insertAtCursor(ta[0], snippet);
$(this).val("");
ta.focus();
});
wrap.append(sel).append($("<br>")).append(ta);
stepDiv.append(wrap);
return ta;
},
output: function (values) {
var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
if (text) {
return "==== Etîmolojî ====\n" + text + "\n\n";
}
// No etymology entered — emit {{ji?|lang}} as a placeholder,
// but only when the entry has at least one regular mane sense
// (not a template sense like {{guharto|…}}).
var hasRegularMane = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var tpl = $(this).find("select.wiktku-dfn-tpl-select").val();
var mane = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!tpl && mane) {
hasRegularMane = true;
return false; // break
}
});
if (!hasRegularMane) return "";
return "==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n\n";
} },
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger when at least one sense uses a template instead of a mane.
var hasTemplateSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
if ($(this).find("select.wiktku-dfn-tpl-select").val()) {
hasTemplateSense = true;
return false; // break
}
});
return !hasTemplateSense;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one translation row: a language dropdown + a growing list
* of word inputs. When the dropdown gets a value the next empty row
* is appended automatically.
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-trans-row'></li>");
// Language selector — chosen is applied after insertion into DOM.
var langSel = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
langSel.attr("data-placeholder", "Zimanekî hilbijêre");
populateMenus(langSel, steps.trans.keys || [], steps.trans.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.trans.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words'></ul>");
var firstWord = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(firstWord));
if (isMobile) {
row.append(wrapNativeSelect(langSel)).append(wordList);
} else {
row.append(langSel).append(wordList);
}
return row;
},
makeWordInput: function () {
var input = $("<textarea></textarea>")
.attr("name", "wiktku-trans-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Tercime…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-trans-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.trans.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(stepDiv);
list.append(newRow);
// Init chosen after the new row is in the DOM (desktop only).
if (!isMobile) newRow.find("select").chosen(chosenOptions);
}
// Keep disabled keys in sync across all lang selectors.
steps.trans.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.trans.disabledKeys);
stepDiv.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-trans-row select").each(function () {
var self = $(this);
var own = self.val();
self.find("option").each(function () {
var code = $(this).val();
if (!code) return;
$(this).prop("disabled", taken[code] && code !== own);
});
self.trigger("chosen:updated");
});
},
build: function (stepDiv) {
if (stepDiv.find("ul.wiktku-trans-list").length) return null;
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(stepDiv));
stepDiv.append(list);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return null;
},
/** Reads all translation rows from the DOM. */
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-trans-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-trans-words textarea").each(function () {
var v = $.trim($(this).val());
if (v) words.push(v);
});
if (words.length) result.push([lang, words]);
});
return result;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var outputString = "\n\n==== Werger ====\n{{werger-ser}}";
if (rows.length) {
// Sort by Kurdish sort key.
rows.sort(function (a, b) {
var aLang = langsByCode[a[0]] || [];
var bLang = langsByCode[b[0]] || [];
return (aLang[2] || "").localeCompare(bLang[2] || "", "ku");
});
outputString += "\n" + $.map(rows, function (row) {
var lang = row[0];
var words = row[1];
var wikiWords = words.map(function (w) {
return "{{W|" + lang + "|" + w + "}}";
}).join(", ");
return "* {{Z|" + lang + "}}: " + wikiWords;
}).join("\n");
}
outputString += "\n{{werger-bin}}\n\n";
return outputString;
}
},
};
steps.trans.keys = steps.lang.choices;
var ordered_steps = [
steps.lang, steps.pron, steps.pos, steps.cinsiyet, steps.lektur, steps.tr,
steps.dfn, steps.je, steps.tekildar,
steps.etym, steps.binereherwiha, steps.trans];
// Step ids that belong to each section (not shared across sections).
var PER_SECTION_STEP_IDS = [
"pos", "cinsiyet", "lektur", "tr",
"dfn", "je", "tekildar", "etym", "binereherwiha", "trans"
];
// ── Multi-section state ──────────────────────────────────────────────────
// Each entry is a plain snapshot: { pos, cinsiyet, lektur, tr, dfn (senses[]),
// je, tekildar, binereherwiha, trans (rows[]) }.
var sections = [{}]; // section 0 starts empty (DOM is the truth)
var activeSection = 0;
/**
* Read dfn senses from DOM into a serialisable array.
* Extends getSenses() with the template fields.
*/
function snapshotDfn() {
return steps.dfn.getSenses($("#wiktku-start-dfn"));
}
/**
* Rebuild the dfn DOM from a previously snapshotted senses array.
*/
function restoreDfn(senses) {
var stepDiv = $("#wiktku-start-dfn");
// Tear down the existing list so build() recreates it cleanly.
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
var list = stepDiv.find("ol.wiktku-dfn-list");
$.each(senses, function (i, sense) {
// Ensure enough blocks exist (build() seeds one).
var blocks = list.find("li.wiktku-dfn-sense");
var block = blocks.eq(i);
if (!block.length) {
var nb = steps.dfn.buildSenseBlock(stepDiv);
list.append(nb);
block = list.find("li.wiktku-dfn-sense").last();
}
// Template selector.
block.find("select.wiktku-dfn-tpl-select").val(sense.tpl || "");
if (sense.tpl) {
block.find("textarea.wiktku-dfn-mane").hide();
block.find("input.wiktku-dfn-tpl-title").val(sense.tplTitle || "").show();
} else {
block.find("textarea.wiktku-dfn-mane").val(sense.mane || "").show();
block.find("input.wiktku-dfn-tpl-title").hide().val("");
}
// Restore a sub-list (etiket, herwiha, hevmane …) from a values array.
function restoreSubList(cls, values) {
if (!values || !values.length) return;
var groupDiv = block.find("." + cls + "-group");
var subList = groupDiv.find("ol, ul").first();
if (!subList.length) return; // group not found
// Fill existing items, append new ones as needed.
$.each(values, function (j, val) {
var items = subList.find("li");
if (j < items.length) {
items.eq(j).find("textarea").val(val);
} else {
var ta = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-restore-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.val(val);
ta.on("input", function () {
steps.dfn.onSubInput(subList, this, 1, true);
});
subList.append($("<li></li>").append(ta));
}
});
}
// Reveal and populate lazy groups that have data.
var lazyMap = {
"wiktku-dfn-etiket": sense.etiket,
"wiktku-dfn-herwiha": sense.herwiha,
"wiktku-dfn-hevmane": sense.hevmane,
"wiktku-dfn-dijmane": sense.dijmane,
"wiktku-dfn-koordine": sense.koordine,
"wiktku-dfn-jornav": sense.jornav,
"wiktku-dfn-jernav": sense.jernav
};
$.each(lazyMap, function (cls, vals) {
if (vals && vals.length) restoreSubList(cls, vals);
});
// Nimûne items are objects { text, tr?, t? } — restore using the builder.
if (sense.nimune && sense.nimune.length) {
var nimuneGroupDiv = block.find(".wiktku-dfn-nimune-group");
var nimuneList = nimuneGroupDiv.find("ol.wiktku-dfn-nimune-list");
var buildFn = nimuneGroupDiv.data("buildNimuneLi");
nimuneList.empty();
$.each(sense.nimune, function (_, n) {
var text = typeof n === "object" ? (n.text || "") : n;
if (!text) return;
var li = buildFn ? buildFn() : $("<li class='wiktku-dfn-nimune-li'></li>");
li.find(".wiktku-dfn-nimune-text").val(text);
if (n.tr) li.find(".wiktku-dfn-nimune-tr").val(n.tr);
if (n.t) li.find(".wiktku-dfn-nimune-t").val(n.t);
nimuneList.append(li);
});
// Always leave a blank trailing item.
if (buildFn) nimuneList.append(buildFn());
}
// Restore jêder (quote/citation) data into the sense-block-level group.
if (sense.jeder && sense.jeder.quote) {
var jederGroup = block.find(".wiktku-dfn-jeder-group");
jederGroup.find(".wiktku-dfn-nimune-quote").val(sense.jeder.quote);
if (sense.jeder.quoteTr) jederGroup.find(".wiktku-dfn-nimune-quote-tr").val(sense.jeder.quoteTr);
if (sense.jeder.quoteT) jederGroup.find(".wiktku-dfn-nimune-quote-t").val(sense.jeder.quoteT);
if (sense.jeder.jêderTpl) {
var srcSel = jederGroup.find(".wiktku-dfn-quote-src-sel");
srcSel.val(sense.jeder.jêderTpl).trigger("change");
if (sense.jeder.jêderFields) {
$.each(sense.jeder.jêderFields, function (key, val) {
jederGroup.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
}
});
}
/**
* Snapshot simple (non-dfn) per-section steps from current DOM into obj.
*/
function saveCurrentSection() {
var snap = {};
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
snap.dfn = snapshotDfn();
return;
}
if (id === "etym") {
snap.etym = $.trim($("#wiktku-start-etym .wiktku-etym-text").val());
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
if (id === "trans") {
snap.trans = steps.trans.getTranslations(stepDiv);
return;
}
// Generic: read all step fields.
var fields = stepDiv.find(".wiktku-start-step-field");
if (step.multiple) {
snap[id] = fields.map(function () { return $(this).val(); }).get();
} else {
snap[id] = fields.val();
}
});
sections[activeSection] = snap;
}
/**
* Restore a previously saved snapshot into the form DOM.
*/
function restoreSection(snap) {
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
restoreDfn(snap.dfn || []);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
$("#wiktku-start-etym .wiktku-etym-text").val(snap.etym || "");
return;
}
if (id === "trans") {
// Rebuild trans rows.
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
steps.trans.build(transDiv);
var rows = snap.trans || [];
$.each(rows, function (i, row) {
var lang = row[0], words = row[1];
var list = transDiv.find("ul.wiktku-trans-list");
var lastRow = list.find("li.wiktku-trans-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-trans-words");
$.each(words, function (j, word) {
var wordItems = wordList.find("li");
if (j < wordItems.length) {
wordItems.eq(j).find("textarea").val(word);
} else {
// .val() below doesn't fire "input", so the normal
// auto-grow never runs — append a matching item
// ourselves instead of silently dropping the word.
var extraInput = steps.trans.makeWordInput();
wordList.append($("<li></li>").append(extraInput));
extraInput.val(word);
}
});
// Leave one trailing empty field so the row can still grow
// when the user types, matching a freshly-built row.
if ($.trim(wordList.children("li").last().find("textarea").val())) {
wordList.append($("<li></li>").append(steps.trans.makeWordInput()));
}
});
return;
}
var step = steps[id];
if (!step) return;
var stepDiv = $("#wiktku-start-" + id);
var fields = stepDiv.find(".wiktku-start-step-field");
var val = snap[id];
if (val === undefined || val === null) return;
if (step.multiple) {
var arr = val;
fields.each(function (i) {
if (i < arr.length) $(this).val(arr[i]);
});
} else {
fields.val(val);
}
// Notify chosen widgets of the programmatic value change.
if (!isMobile) fields.filter("select").trigger("chosen:updated");
});
}
/**
* Produce wikitext for the currently-visible form state.
* This is identical to the old getWikitext but returns via callback.
*/
function getWikitextForCurrentSection(callback) {
var values = getValues();
var entry = steps.pos.output(values);
steps.dfn.getOutput(values, function (output) {
entry += output;
entry += steps.je.output(values);
entry += steps.tekildar.output(values);
entry += steps.etym.output(values);
entry += steps.binereherwiha.output(values);
entry += steps.trans.output(values);
callback(entry, values);
});
}
/**
* Collect wikitext from ALL sections by save→restore→generate cycling,
* then restore the originally active section.
*/
function getWikitextAllSections(callback) {
saveCurrentSection();
var results = new Array(sections.length);
var sharedValues = getValues(); // lang/pron are shared
function processSection(i) {
if (i >= sections.length) {
// All done — restore original active section.
restoreSection(sections[activeSection]);
refresh();
callback(results, sharedValues);
return;
}
restoreSection(sections[i]);
refresh();
getWikitextForCurrentSection(function (sectionText) {
results[i] = sectionText;
processSection(i + 1);
});
}
processSection(0);
}
/**
* The original getWikitext — now assembles all sections plus lang header.
*/
function getWikitext(callback) {
getWikitextAllSections(function (sectionTexts, sharedValues) {
var entry = steps.lang.output(sharedValues);
entry += steps.pron.output(sharedValues);
entry += sectionTexts.join("\n");
// Edit summary uses section 0's values. Read from the saved snapshot
// (not the live DOM) so it doesn't mix section 0's pos with whichever
// section happens to be active/restored at this point.
var dfnSenses = (sections[0] && sections[0].dfn) || [];
var dfnSummary = dfnSenses.map(function (s) { return s.mane; }).filter(Boolean).join("; ");
var summary = "([[Mediawiki:Gadget-start.js|WF:Nû]]) +" +
sharedValues.lang + ":" + sections[0].pos + ":" + dfnSummary;
document.getElementById("wpSummary").value = summary;
callback(entry);
});
}
var continueBtn;
function getValuesForStep(stepId) {
var fields = $("#wiktku-start-" + stepId + " .wiktku-start-step-field");
var step = steps[stepId];
if (step.keys) {
var values = {};
fields.each(function (i, field) {
var key = $(field).prevAll(".wiktku-start-step-keyfield").val();
if (key) values[key] = $(field).val();
});
return values;
}
else if (step.multiple) {
return fields.map(function (i) {
return $(this).val();
}).get();
}
return fields.val();
}
function getValues() {
var values = {};
$.each(steps, function (stepId) {
values[stepId] = getValuesForStep(stepId);
});
return values;
}
function populateMenus(inputs, choices, disabledValues) {
if (!disabledValues) disabledValues = {};
var vals = inputs.map(function (i, input) {
return $(input).val();
});
inputs.empty();
inputs.append($("<option></option>"));
$.each(choices, function (j, choice) {
// Append the language code in parentheses so that typing a code
// (e.g. "ku") in the search box still finds the language name.
var displayText = capitalize(choice[1]);
if (choice[2] !== undefined) {
// This is a language choice [code, name, sortKey] — show code.
displayText = capitalize(choice[1]) + " (" + choice[0] + ")";
}
var option = $(mw.html.element("option", {
value: choice[0] }, displayText));
if (disabledValues[choice[0]]) option.prop("disabled", true);
inputs.append(option);
});
inputs.val(function (i) {
return vals[i];
});
}
/**
* Returns a bitmap containing the keys that should be disabled for a key
* menu in the given step because they are disabled or already taken by
* another key menu.
*/
function getDisabledKeys(step) {
var occupiedKeys = {};
$("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function (i, select) {
occupiedKeys[$(this).val()] = true;
});
if (step.disabledKeys) $.extend(occupiedKeys, step.disabledKeys);
return occupiedKeys;
}
function buildKeyInput(step) {
if (!step.keys) return undefined;
var input = $(mw.html.element("select", {
"class": "wiktku-start-step-keyfield wiktku-start-narrow" }));
input.attr("data-placeholder", "Hilbijêre " + step.keyName);
if (isMobile) {
populateMenus(input, step.keys, getDisabledKeys(step));
// On mobile return the wrapper; the select is inside it.
// Change events still fire on the inner select.
return wrapNativeSelect(input);
}
input.on("chosen:showing_dropdown", function (evt, context) {
$(this).data("wiktku-defaultValue", $(this).val());
});
input.change(function (evt, context) {
var inputs = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").not(this);
var oldValue = $(this).data("wiktku-defaultValue");
var newValue = context.selected;
inputs.find("option[value='" + oldValue + "']").prop('disabled', false);
inputs.find("option[value='" + newValue + "']").prop('disabled', true);
inputs.trigger("chosen:updated");
});
populateMenus(input, step.keys, getDisabledKeys(step));
return input;
}
/**
* If the current text field has text and there are no more text fields after
* the current text field in the list, add another text field to the list.
*/
function refreshForTextField(currentInput, step) {
currentInput = $(currentInput);
var value = currentInput.val();
var item = currentInput.parent();
if (value && !item.next("li").length) {
var nextInput = $("<textarea></textarea>")
.attr("name", "wiktku-field-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("class", currentInput.attr("class"))
.attr("rows", currentInput.attr("rows") || 1);
nextInput.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var nextKeyInput = buildKeyInput(step);
var nextItem = $("<li></li>").append(nextKeyInput).append(nextInput);
item.parent().append(nextItem);
if (nextKeyInput) nextKeyInput.chosen(chosenOptions);
}
var canContinue = !continueBtn.prop("disabled");
if ((value && !canContinue) || (!value && canContinue)) {
refresh(step);
}
}
function prepareInput(input, step) {
if (!input) return;
if (step.required) input.prop('required', true);
input.change(step, refresh);
}
/**
* Shows and hides all the steps based on whether their prerequisites are met,
* and updates placeholders where applicable.
*/
function refresh(evt) {
var values = getValues();
var changedStep = evt && evt.data;
var didFocus = false;
var canContinue = true;
// Re-filter template options in every sense block whenever lang changes.
$("#wiktku-start-dfn .wiktku-dfn-tpl-select").each(function () {
var fn = $(this).data("updateOptions");
if (typeof fn === "function") fn();
});
// Re-filter pronunciation and etymology template dropdowns when language changes.
steps.pron.refreshTplSelect();
steps.etym.refreshTplSelect();
// Sync tr/t sub-fields in every nimûne item to the current language.
// tr shown when language needs transliteration; t shown when lang !== "ku".
(function () {
var lang = values.lang || "";
var showTr = needsTransliteration(lang);
var showT = lang && lang !== "ku";
$("#wiktku-start-dfn .wiktku-dfn-nimune-list li.wiktku-dfn-nimune-li").each(function () {
var li = $(this);
var mainTa = li.find(".wiktku-dfn-nimune-text");
// Ensure the sub-wrapper exists when we need it.
var subWrap = li.find(".wiktku-dfn-nimune-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
trTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-tr-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-tr")
.attr("placeholder", "Transkrîpsiyon…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-nimune-sub");
li.append(subWrap);
}
tTa = $("<textarea></textarea>")
.attr("name", "wiktku-dfn-nimune-t-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 5)
.attr("class", "wiktku-dfn-subfield wiktku-dfn-nimune-t")
.attr("placeholder", "Tercime (kurmancî)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-nimune-sub");
if (subWrap.length && !subWrap.children().length) subWrap.remove();
});
}());
$.each(steps, function (stepId, step) {
if (typeof(step.visible) === "function" && !step.visible(values)) {
$("#wiktku-start-" + stepId).slideUp();
// $("#wiktku-start-" + stepId + " .wiktku-start-step-field").val("");
}
else {
var stepDiv = $("#wiktku-start-" + stepId);
if (changedStep !== step && typeof(step.build) === "function") {
prepareInput(step.build(stepDiv, values), step);
}
var input = stepDiv.find(".wiktku-start-step-field");
if (typeof(step.example) === "function") {
// .find() above already reaches nested fields (e.g. the dfn
// step's mane textareas inside each sense block), so one
// assignment covers every step; dfn keeps its own fallback.
var exampleText = step.example(values) || (step.id === "dfn" ? "Mane…" : "");
input.attr("placeholder", exampleText);
}
var didSlideDown;
if (!didFocus && stepDiv.css("display") === "none" && step.required) {
didSlideDown = function (evt) {
input.focus();
};
didFocus = true;
}
stepDiv.slideDown(didSlideDown);
}
if (step.required &&
(values[stepId] === "" ||
(step.multiple && values[stepId].join("") === ""))) {
canContinue = false;
}
});
continueBtn.button(canContinue ? "enable" : "disable");
}
function destroy() {
$("#wiktku-start-form, .noafterwizard").slideUp(function () {
$(this).remove();
});
$(".noarticletext .nowizard, #editform").slideDown();
$("#ca-edit").removeClass("selected");
$("#ca-wiktku-nowizard").addClass("selected");
}
function build() {
$(".nowizard, .nowizard .noafterwizard").hide();
var callToAction = $("#wiktku-calltoaction");
var origCallToActionText = callToAction.text();
$(mw.util.addPortletLink("p-views", "#", "Edîtora çavkaniyê veke",
"ca-wiktku-nowizard", "Vê rûpelê bi edîtora çavkaniyê çêke",
undefined, "#ca-watch")).click(function (evt) {
evt.preventDefault();
callToAction.text(origCallToActionText);
destroy();
});
callToAction.text(origCallToActionText +
" Forma li jêr ji bo çêkirina madeyeke nû bi kar bîne.");
var startForm = $("<form id='wiktku-start-form'></form>");
var spinner;
// Tab bar for switching between POS sections.
var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>");
startForm.submit(function (evt) {
evt.preventDefault();
continueBtn.button("disable");
spinner.show();
getWikitext(function (wikitext) {
$("#wpTextbox1").val(wikitext);
$("html, body").animate({scrollTop: 0});
callToAction.text("Hindik ma!");
$("#wiktku-preview-container").remove();
destroy();
});
});
$.each(ordered_steps, function (i, step) {
var stepDiv = $(mw.html.element("div", {
"class": "wiktku-start-step",
id: "wiktku-start-" + step.id }));
var name = capitalize(step.name);
stepDiv.append($(mw.html.element("h3", {
"class": "wiktku-start-step-name" }, new mw.html.Raw(mw.html.element("label", {
"for": "wiktku-start-" + step.id + "-field" }, name)))));
if (step.question_fmt) {
var question = step.question_fmt.replace(/\{\{PAGENAME\}\}/g, pageName);
stepDiv.append($(mw.html.element("label", {
"class": "wiktku-start-step-question",
"for": "wiktku-start-" + step.id + "-field" }, question)));
if (step.question_br) stepDiv.append($("<br>"));
}
var input;
// Menu
if (step.choices) {
input = $(mw.html.element("select", {
"class": "wiktku-start-step-field",
id: "wiktku-start-" + step.id + "-field" }));
input.attr("data-placeholder",
capitalize(step.name) + " hilbijêre ");
populateMenus(input, step.choices);
if (step.multiple) input.attr("multiple", true);
if (isMobile) {
stepDiv.append(wrapNativeSelect(input));
} else {
stepDiv.append(input);
}
}
// Custom
else if (typeof(step.build) === "function") {
input = step.build(stepDiv);
}
// Text field(s)
else {
input = $("<textarea></textarea>")
.attr("class", "wiktku-start-step-field")
.attr("id", "wiktku-start-" + step.id + "-field")
.attr("rows", step.rows || 2);
if (step.narrow) input.addClass("wiktku-start-narrow");
if (step.multiple) {
input.on("input", function (evt) {
refreshForTextField(evt.target, step);
});
var keyInput = buildKeyInput(step);
var list = $(step.ordered ? "<ol></ol>" : "<ul></ul>")
.append($("<li></li>").append(keyInput).append(input));
stepDiv.append(list);
}
else stepDiv.append(input);
}
prepareInput(input, step);
stepDiv.hide();
// Insert tab bar just before the first per-section step.
if (step.id === "pos") startForm.append(sectionTabsDiv);
startForm.append(stepDiv);
});
// ── Section tab helpers ──────────────────────────────────────────────
/** Re-render the tab bar to reflect current sections[] and activeSection. */
function renderSectionTabs() {
sectionTabsDiv.empty();
// Hide the tab bar entirely until a language is chosen.
var lang = getValues().lang || "";
if (!lang) {
sectionTabsDiv.hide();
return;
}
sectionTabsDiv.show();
$.each(sections, function (i) {
// Use the stored pos value for the label if available.
var posVal = sections[i].pos || "";
var tabLabel = posVal ? capitalize(posVal) : ("Beş " + (i + 1));
var tab = $("<span></span>")
.addClass("wiktku-section-tab")
.text(tabLabel)
.toggleClass("wiktku-tab-active", i === activeSection);
(function (idx) {
tab.on("click", function () {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
});
}(i));
sectionTabsDiv.append(tab);
});
}
/** Switch to section idx, saving current first. */
function switchToSection(idx) {
if (idx === activeSection) return;
saveCurrentSection();
activeSection = idx;
restoreSection(sections[activeSection]);
refresh();
renderSectionTabs();
}
renderSectionTabs();
// Update the active tab's label whenever pos changes.
startForm.on("change", "#wiktku-start-pos-field", function () {
renderSectionTabs();
});
// Show the tab bar as soon as a language is selected.
startForm.on("change", "#wiktku-start-lang-field", function () {
renderSectionTabs();
});
var footer = $("<div id='wiktku-start-footer'></div>");
spinner = $(mw.html.element("img", {
id: "wiktku-start-spinner",
src: "//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif",
alt: "Tê barkirin…",
title: "Tê barkirin…" }));
footer.append(spinner.hide());
continueBtn = $(mw.html.element("button", {
id: "wiktku-unhide-editform",
type: "submit" }, "Bişîne"));
footer.append(continueBtn);
// ── Add-section button ───────────────────────────────────────────────
var addSectionBtn = $(mw.html.element("button", {
id: "wiktku-add-section",
type: "button" }, "+ Beş zêde bike"));
addSectionBtn.css("margin-left", "6px");
addSectionBtn.on("click", function () {
saveCurrentSection();
sections.push({}); // new empty section
activeSection = sections.length - 1;
// Clear all per-section fields so the new section starts blank.
$.each(PER_SECTION_STEP_IDS, function (_, id) {
if (id === "dfn") {
var stepDiv = $("#wiktku-start-dfn");
stepDiv.find("ol.wiktku-dfn-list").remove();
steps.dfn.build(stepDiv);
return;
}
if (id === "etym") {
$("#wiktku-start-etym .wiktku-etym-wrap").remove();
steps.etym.build($("#wiktku-start-etym"));
return;
}
if (id === "trans") {
var transDiv = $("#wiktku-start-trans");
transDiv.find("ul.wiktku-trans-list").remove();
return;
}
var stepDiv = $("#wiktku-start-" + id);
stepDiv.find(".wiktku-start-step-field").val("");
if (!isMobile) stepDiv.find("select.wiktku-start-step-field").trigger("chosen:updated");
});
renderSectionTabs();
refresh();
// Scroll to the tab bar so the user sees the new section.
$("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300);
});
footer.append(addSectionBtn);
// ── Preview checkboxes ───────────────────────────────────────────────
// Wikitext preview (raw text panel)
var previewCheck = $("<input type='checkbox' id='wiktku-preview-toggle'>");
var previewLabel = $("<label for='wiktku-preview-toggle'></label>")
.text(" Pêşdîtina wîkîtekstê");
var previewPanel = $("<pre id='wiktku-preview-panel'></pre>").hide();
// Live rendered preview (parsed HTML panel, same logic as AjaxEdit).
// Not available on mobile — API polling causes too many problems on small screens.
var livePreviewCheck = null;
var livePreviewPanel = null;
if (!isMobile) {
livePreviewCheck = $("<input type='checkbox' id='wiktku-live-preview-toggle'>");
livePreviewPanel = $("<div id='wiktku-live-preview-panel'></div>").hide();
}
// Container that holds both panels and switches between stacked / side-by-side.
var previewContainer = $("<div id='wiktku-preview-container'></div>");
previewContainer.append(previewPanel);
if (!isMobile) previewContainer.append(livePreviewPanel);
var previewTimer = null;
var livePreviewIntervalId = -1;
/** Rebuilds wikitext preview if its checkbox is checked. */
function schedulePreview() {
if (!previewCheck.prop("checked")) return;
clearTimeout(previewTimer);
// Debounce: wait 400 ms after the last keystroke before rebuilding.
previewTimer = setTimeout(function () {
getWikitext(function (wikitext) {
previewPanel.text(wikitext).show();
updatePanelLayout();
});
}, 400);
}
/** Fetches parsed HTML and populates the live preview panel. */
function loadLivePreview() {
getWikitext(function (wikitext) {
new mw.Api().parse(wikitext, { title: mw.config.get("wgPageName") }).done(function (html) {
livePreviewPanel.html(html).show();
updatePanelLayout();
});
});
}
/** Adjusts panel widths depending on which previews are visible. */
function updatePanelLayout() {
var wikitextVisible = previewCheck.prop("checked");
var liveVisible = livePreviewCheck && livePreviewCheck.prop("checked");
if (wikitextVisible && liveVisible) {
// Side by side — each panel takes roughly half the available width.
previewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
livePreviewPanel.css({ "flex": "1 1 45%", "min-width": "280px" });
} else {
// Full width for whichever is visible.
previewPanel.css({ "flex": "1 1 100%", "min-width": "" });
if (livePreviewPanel) livePreviewPanel.css({ "flex": "1 1 100%", "min-width": "" });
}
}
previewCheck.on("change", function () {
if ($(this).prop("checked")) {
schedulePreview();
} else {
clearTimeout(previewTimer);
previewPanel.hide();
updatePanelLayout();
}
});
if (!isMobile) {
livePreviewCheck.on("change", function () {
if ($(this).prop("checked")) {
livePreviewPanel.show();
loadLivePreview();
livePreviewIntervalId = setInterval(loadLivePreview, 500);
} else {
clearInterval(livePreviewIntervalId);
livePreviewIntervalId = -1;
livePreviewPanel.hide().empty();
updatePanelLayout();
}
});
}
// Listen on all input/change events on the form and update both previews.
startForm.on("input change", function () {
schedulePreview();
});
footer.append($("<span style='margin-left:1em'></span>")
.append(previewCheck).append(previewLabel));
if (!isMobile) {
var livePreviewLabel = $("<label for='wiktku-live-preview-toggle'></label>")
.text(" Pêşdîtina zindî");
footer.append($("<span style='margin-left:1em'></span>")
.append(livePreviewCheck).append(livePreviewLabel));
}
startForm.append(footer);
$("#editform").hide().before(startForm);
// Insert preview container (holds both panels) after the form.
startForm.after(previewContainer);
if (!isMobile) startForm.find("select").chosen(chosenOptions);
continueBtn.button();
refresh();
// Zimanan ji MediaWiki:Gadget-translation_editor.js/ziman.json bar bike.
// Kodên ku bi "-pro" diqedin û navên ku "zimanê destan" tê de heye
// tên derxistin. Zimanên xardkirî li serî dimînin, yên din
// bi alfabeyê li dû wan tên.
// Pinned choices come from MediaWiki:Gadget-start.js/data.json (langChoices),
// already loaded into steps.lang.choices before build() runs.
var pinnedChoices = steps.lang.choices.slice();
var pinnedCodes = $.map(pinnedChoices, function (choice) { return choice[0]; });
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-translation_editor.js/ziman.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var zimanData;
try { zimanData = JSON.parse(content); } catch (e) { zimanData = {}; }
var extraChoices = [];
$.each(zimanData, function (code, name) {
// Filter: skip proto-language codes and legendary/reconstructed langs.
if (/-pro$/i.test(code)) return;
if (/ziman[eê]\s+destan/i.test(name)) return;
// Skip codes already in the pinned list (they are handled above).
if (pinnedCodes.indexOf(code) !== -1) return;
// sortKey: bare name without leading "zimanê " for sorting.
var sortKey = name.replace(/^ziman[eê]\s+/i, "");
var choice = [code, name, sortKey];
extraChoices.push(choice);
langsByCode[code] = choice;
});
// Populate langsByCode for pinned choices too.
$.each(pinnedChoices, function (i, choice) {
// Ensure pinned choices have a sortKey (index 2).
if (choice.length < 3) choice[2] = choice[1];
langsByCode[choice[0]] = choice;
});
// Sort the extra choices alphabetically by sort key.
extraChoices.sort(function (a, b) {
return a[2].localeCompare(b[2], userLang);
});
// Final list: pinned first, then the rest.
var allChoices = pinnedChoices.concat(extraChoices);
steps.lang.choices = allChoices;
steps.trans.keys = allChoices;
var langMenu = $("#wiktku-start-lang-field");
populateMenus(langMenu, steps.lang.choices);
langMenu.trigger("chosen:updated");
var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield");
populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans));
transMenus.trigger("chosen:updated");
});
}
mw.loader.using(["jquery.chosen", "jquery.ui", "mediawiki.api"], function () {
// Load metadata, langChoices, posChoices and tplDefs from the companion
// data page so they can be updated without touching this script.
new mw.Api().get({
action: "query",
prop: "revisions",
titles: "MediaWiki:Gadget-start.js/data.json",
rvprop: "content",
rvslots: "main",
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page &&
page.revisions &&
page.revisions[0].slots.main.content;
var d;
try { d = JSON.parse(content); } catch (e) { d = {}; }
// Populate metadata.
if (d.metadata) $.extend(metadata, d.metadata);
// Populate lang choices (pinned list used by build() → ziman.json loader).
if (d.langChoices) steps.lang.choices = d.langChoices;
// Populate POS choices.
if (d.posChoices) steps.pos.choices = d.posChoices;
// Populate template definitions for the dfn sense-block builder.
if (d.tplDefs) steps.dfn.tplDefs = d.tplDefs;
// Populate pos placeholder examples.
if (d.posExamples) steps.dfn.posExamples = d.posExamples;
// Populate citation template definitions for the quote widget.
if (d.jederDefs) steps.dfn.jederDefs = d.jederDefs;
// Populate pronunciation and etymology template insert lists.
if (d.pronTpls) {
steps.pron.pronTpls = d.pronTpls;
steps.pron.refreshTplSelect();
}
if (d.etymTpls) {
steps.etym.etymTpls = d.etymTpls;
steps.etym.refreshTplSelect();
}
// Sync trans keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
8fo8c6bay2r0zq71qt5igm39ungsqhm
Bikarhêner:Wikihez/minerva.js
2
970182
6241655
6033537
2026-07-11T19:42:11Z
Wikihez
7344
Rûpel hat valakirin
6241655
javascript
text/javascript
phoiac9h4m842xq45sp7s6u21eteeq1
Bikarhêner:Wikihez/vector-2022.css
2
1325005
6241656
6241199
2026-07-11T19:42:25Z
Wikihez
7344
Rûpel hat valakirin
6241656
css
text/css
phoiac9h4m842xq45sp7s6u21eteeq1
Bikarhêner:Wikihez/skrîpt/json/loader-settings.json
2
1357332
6241607
6241606
2026-07-11T12:50:14Z
Wikihez
7344
Mîhengên Loaderê hatin nûkirin (bi rêza alfabetîk)
6241607
json
application/json
{
"scripts": [
{
"key": "etiketCeke",
"label": "Etîket Çêke",
"src": "Bikarhêner:Wikihez/skrîpt/loader/etîket-çêke.js",
"info": "Ji bo şablona {{f}} etîketên nû li Modulê zêde dike.",
"disabled": false
},
{
"key": "mass-delete-category",
"label": "Jêbirina bi kom",
"src": "Bikarhêner:Wikihez/skrîpt/js/delete.js",
"info": "Rûpelên di kategoriyê de bi komî jê dibe (Taybet ji bo adminan)",
"disabled": false
},
{
"key": "kopi-enwikt",
"label": "Kopî enwikt",
"src": "Bikarhêner:Wikihez/skrîpt/js/kopi-enWikt.js",
"info": "Rûpelan ji Wîkîferhenga îngilîzî kopî dike û girêdanên Wîkîdaneyê çêdike.",
"disabled": false
},
{
"key": "test",
"label": "test.js",
"src": "Bikarhêner:Wikihez/test.js",
"info": "Rûpel: Bikarhêner:Wikihez/test.js",
"disabled": false
}
]
}
lr2v2zlee3jkxejb3wiij2sjo61s2ge
6241608
6241607
2026-07-11T12:50:54Z
Wikihez
7344
Restored revision 6241606 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241608
json
application/json
{
"scripts": [
{
"key": "etiketCeke",
"label": "Etîket Çêke",
"src": "Bikarhêner:Wikihez/skrîpt/loader/etîket-çêke.js",
"info": "Ji bo şablona {{f}} etîketên nû li Modulê zêde dike.",
"disabled": false
},
{
"key": "mass-delete-category",
"label": "Jêbirina bi kom",
"src": "Bikarhêner:Wikihez/skrîpt/js/delete.js",
"info": "Rûpelên di kategoriyê de bi komî jê dibe (Taybet ji bo adminan)",
"disabled": false
},
{
"key": "kopi-enwikt",
"label": "Kopî enwikt",
"src": "Bikarhêner:Wikihez/skrîpt/js/kopi-enWikt.js",
"info": "Rûpelan ji Wîkîferhenga îngilîzî kopî dike û girêdanên Wîkîdaneyê çêdike.",
"disabled": false
}
]
}
patlcxa5sx0f1rg8oicmxg7siy3qlfj
6241682
6241608
2026-07-11T22:22:32Z
Wikihez
7344
Mîhengên Loaderê hatin nûkirin (bi rêza alfabetîk)
6241682
json
application/json
{
"scripts": [
{
"key": "etiketCeke",
"label": "Etîket Çêke",
"src": "Bikarhêner:Wikihez/skrîpt/loader/etîket-çêke.js",
"info": "Ji bo şablona {{f}} etîketên nû li Modulê zêde dike.",
"disabled": false
},
{
"key": "formatherf",
"label": "formatherf.js",
"src": "Bikarhêner:Wikihez/skrîpt/js/formatherf.js",
"info": "Rûpel: Bikarhêner:Wikihez/skrîpt/js/formatherf.js",
"disabled": false
},
{
"key": "mass-delete-category",
"label": "Jêbirina bi kom",
"src": "Bikarhêner:Wikihez/skrîpt/js/delete.js",
"info": "Rûpelên di kategoriyê de bi komî jê dibe (Taybet ji bo adminan)",
"disabled": false
},
{
"key": "kopi-enwikt",
"label": "Kopî enwikt",
"src": "Bikarhêner:Wikihez/skrîpt/js/kopi-enWikt.js",
"info": "Rûpelan ji Wîkîferhenga îngilîzî kopî dike û girêdanên Wîkîdaneyê çêdike.",
"disabled": false
}
]
}
krr2l1rzbwyzrlwklvywpgz8bv0wx8g
6241684
6241682
2026-07-11T22:25:02Z
Wikihez
7344
Mîhengên Loaderê hatin nûkirin (bi rêza alfabetîk)
6241684
json
application/json
{
"scripts": [
{
"key": "etiketCeke",
"label": "Etîket Çêke",
"src": "Bikarhêner:Wikihez/skrîpt/loader/etîket-çêke.js",
"info": "Ji bo şablona {{f}} etîketên nû li Modulê zêde dike.",
"disabled": false
},
{
"key": "mass-delete-category",
"label": "Jêbirina bi kom",
"src": "Bikarhêner:Wikihez/skrîpt/js/delete.js",
"info": "Rûpelên di kategoriyê de bi komî jê dibe (Taybet ji bo adminan)",
"disabled": false
},
{
"key": "kopi-enwikt",
"label": "Kopî enwikt",
"src": "Bikarhêner:Wikihez/skrîpt/js/kopi-enWikt.js",
"info": "Rûpelan ji Wîkîferhenga îngilîzî kopî dike û girêdanên Wîkîdaneyê çêdike.",
"disabled": false
}
]
}
patlcxa5sx0f1rg8oicmxg7siy3qlfj
MediaWiki:Gadget-start.js/data.json
8
1357737
6241609
2026-07-11T13:35:34Z
Wikihez
7344
Rûpel bi "{ "metadata": { "aa":{"haswikt":1,"sc":["Latn","Ethi"]}, "ab":{"haswikt":1,"sc":["Cyrl","Latn","Geor"]}, "aer":{"sc":"Latn"}, "af":{"g":["y","p"],"haswikt":1}, "ak":{"haswikt":1}, "akk":{"g":["n","m","n-p","m-p"],"sc":"Xsux"}, "als":{"haswikt":1}, "am":{"g":["n","m","n-p","m-p"],"haswikt":1,"sc":"Ethi"}, "an":{"g":["n","m","n-p","m-p"],"haswikt":1}, "ang":{"alt":1,"g":["n","m","nt","n-p","m-p","nt-p"],"haswikt":1}, "ar"..." hat çêkirin
6241609
json
application/json
{
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
},
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "Romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
]
},
{
"name": "ku-Arab",
"langs": [
"ku"
]
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
]
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
]
}
]
}
6r8x43arbnfrmzvsxt9tnmnvd31kctu
6241613
6241609
2026-07-11T14:03:42Z
Wikihez
7344
6241613
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "Romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
]
},
{
"name": "ku-Arab",
"langs": [
"ku"
]
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
]
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
]
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
d3ryfrmlrhq6pdunsjh5orn43juviin
6241616
6241613
2026-07-11T14:25:55Z
Wikihez
7344
6241616
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "Romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
r1qiqrpv12gkioy21ek0rrkozgl4d5s
6241635
6241616
2026-07-11T16:25:47Z
Wikihez
7344
6241635
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "Romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
qdyeivgm93skizwrrq4x6s6oe3jgf6q
6241638
6241635
2026-07-11T16:43:01Z
Wikihez
7344
6241638
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "Romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "kîte",
"desc": "Hece şablonê (kurmancî û zimanên din)",
"snippet": "{{kîte|LANG|he|ce|le}}"
},
{
"name": "IPA",
"desc": "Navneteweyî alfabe dengî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
r31ce3djto1rg39p0k78fil0p0ygcyl
6241701
6241638
2026-07-11T23:39:32Z
Wikihez
7344
6241701
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}"
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
bv0ayt30ndu1qmpwcpheziazz50q82o
6241728
6241701
2026-07-12T10:10:28Z
Wikihez
7344
6241728
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}"
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
oectkla47zhc90l2wgf6xw3w4xnlmfc
6241729
6241728
2026-07-12T10:11:19Z
Wikihez
7344
6241729
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}"
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"p"
]
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
f12meh5zq6n6jqjfav9z2795zta3x3k
6241732
6241729
2026-07-12T10:28:52Z
Wikihez
7344
6241732
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
a637o8dkidjbsuem4zzkj62dv8rm8t4
6241733
6241732
2026-07-12T10:32:24Z
Wikihez
7344
6241733
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}",
"langs": [
"ku"
]
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"p"
]
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
7axl1h3cxgq0ljgzxic7j7gs0luoc0d
6241738
6241733
2026-07-12T10:49:54Z
Wikihez
7344
6241738
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}",
"langs": [
"ku"
]
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"p"
]
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
f6crnae6w3agb76qyilxybj4eqkw6ui
6241741
6241738
2026-07-12T10:53:27Z
Wikihez
7344
Restored revision 6241732 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241741
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
a637o8dkidjbsuem4zzkj62dv8rm8t4
6241748
6241741
2026-07-12T11:49:32Z
Wikihez
7344
6241748
json
application/json
{
"langChoices": [
[
"ku",
"kurmancî"
],
[
"zza",
"zazakî"
],
[
"ckb",
"soranî"
],
[
"sdh",
"kurdiya başûrî"
],
[
"de",
"almanî"
],
[
"ar",
"erebî"
],
[
"fa",
"farisî"
],
[
"fr",
"fransî"
],
[
"fi",
"fînî"
],
[
"en",
"îngilîzî"
],
[
"sv",
"swêdî"
],
[
"tr",
"tirkî"
]
],
"posChoices": [
[
"navdêr",
"Navdêr (îsm)"
],
[
"lêker",
"Lêker (fiîl)"
],
[
"rengdêr",
"Rengdêr (sifet)"
],
[
"hoker",
"Hoker (zerf)"
],
[
"serenav",
"Serenav (îsmê xisûsî)"
],
[
"artîkel",
"Artîkel"
],
[
"baneşan",
"Baneşan (nîda)"
],
[
"bazinedaçik",
"Bazinedaçek"
],
[
"cînav",
"Cînav (zemîr)"
],
[
"daçek",
"Daçek (edat)"
],
[
"girêdek",
"Girêdek"
],
[
"gotineke pêşiyan",
"Gotineke pêşiyan"
],
[
"hejmar",
"Hejmar"
],
[
"hevok",
"Hevok (cimle)"
],
[
"îfade",
"Îfade"
],
[
"kurtenav",
"Kurtenav"
],
[
"navgir",
"Navgir"
],
[
"paşdaçek",
"Paşdaçek"
],
[
"paşgir",
"Paşgir"
],
[
"pêşdaçek",
"Pêşdaçek"
],
[
"pêşgir",
"Pêşgir"
],
[
"pirtik",
"Pirtik"
],
[
"reh",
"Reh"
],
[
"sembol",
"Sembol"
],
[
"tîp",
"Tîp (herf)"
]
],
"posExamples": {
"navdêr": "Kelîmeyên ji bo tiştan (sêv, heywan, qedeh) yan terman (dilşadî, bextiyarî hwd.) di rêzimanê de.",
"lêker": "Kelîmeyên ji bo kirin an bûyînê wekî 'nivîsîn' yan 'xeber dan'.",
"rengdêr": "Kelîmeyên ku wesfa navdêran nîşan didin wekî 'sêva sor' yan 'xwarina şîrîn'.",
"hoker": "Kelîmeyên ku dem, cih yan awayê kirinê diyar dikin wekî 'bi vî awayî' yan 'demkî'.",
"daçek": "Kelîmeyên ku cih, dem yan hereketê diyar dikin wekî 'di.. de' yan 'ji'.",
"cînav": "Kelîmeyên ku li şûna navdêran tên bikaranîn daku navdêr neyên dubarekirin wekî 'ew' yan 'em'.",
"baneşan": "Kelîmeyên ku hest, deng hwd. îfade dikin wekî 'noşî!' yan 'aferîn'.",
"serenav": "Navdêrên ku şexsiyetên ferdî nîşan didin, wek navên kes, cih an organîzasyonan nimûne 'London' yan 'Diyarbekir'.",
"gotineke pêşiyan": "Gotinên ku di nav xelkê de bi berbelavî tên bikaranîn bo nimûne 'Serê neêşe ne hewceyî destmalê ye'."
},
"tplDefs": [
{
"name": "guharto",
"langs": null
},
{
"name": "hevmaneya",
"langs": null
},
{
"name": "awayekî din",
"langs": null
},
{
"name": "pirjimar",
"langs": null
},
{
"name": "romanization",
"langs": null
},
{
"name": "awayê Jacobsonê",
"langs": [
"zza"
]
},
{
"name": "ku-Latn",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ku-Arab",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "ckb-Latn",
"langs": [
"ckb"
],
"noLang": true
},
{
"name": "ckb-Arab",
"langs": [
"ckb"
],
"noLang": true
}
],
"jederDefs": {
"jêder-kitêb": {
"label": "Kitêb",
"fields": [
{
"key": "nivîskar",
"label": "Nivîskar"
},
{
"key": "sernav",
"label": "Sernav"
},
{
"key": "sernavê orjînal",
"label": "Sernavê orjînal"
},
{
"key": "terciman",
"label": "Terciman"
},
{
"key": "weşanxane",
"label": "Weşanxane"
},
{
"key": "cih",
"label": "Cih"
},
{
"key": "sal",
"label": "Sal"
},
{
"key": "sala orjînal",
"label": "Sala orjînal"
},
{
"key": "çap",
"label": "Çap"
},
{
"key": "rûpel",
"label": "Rûpel"
},
{
"key": "isbn",
"label": "ISBN"
},
{
"key": "url",
"label": "URL"
}
]
},
"jêder-kovar": {
"label": "Kovar",
"fields": [
{
"key": "nivîskar",
"label": "Nivîskar"
},
{
"key": "nivîskar2",
"label": "Nivîskar 2"
},
{
"key": "sernav",
"label": "Sernav"
},
{
"key": "sernavê orjînal",
"label": "Sernavê orjînal"
},
{
"key": "kovar",
"label": "Kovar"
},
{
"key": "terciman",
"label": "Terciman"
},
{
"key": "weşanxane",
"label": "Weşanxane"
},
{
"key": "cild",
"label": "Cild"
},
{
"key": "hejmar",
"label": "Hejmar"
},
{
"key": "sal",
"label": "Sal"
},
{
"key": "rûpel",
"label": "Rûpel"
},
{
"key": "url",
"label": "URL"
}
]
},
"jêder-malper": {
"label": "Malper",
"fields": [
{
"key": "nivîskar",
"label": "Nivîskar"
},
{
"key": "sernav",
"label": "Sernav"
},
{
"key": "terciman",
"label": "Terciman"
},
{
"key": "malper",
"label": "Malper"
},
{
"key": "url",
"label": "URL"
},
{
"key": "arşîv",
"label": "Arşîv URL"
},
{
"key": "sal",
"label": "Sal"
}
]
}
},
"pronTpls": [
{
"name": "ku-kîte",
"desc": "Şablona hecekirinê ji bo kurmancîz",
"snippet": "* {{ku-kîte}}",
"langs": [
"ku"
],
"noLang": true
},
{
"name": "kîte",
"desc": "Şablona hecekirinê",
"snippet": "{{kîte|LANG|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|LANG|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|LANG|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|peyv|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|LANG|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|LANG|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|LANG|…}}"
},
{
"name": "hv",
"desc": "Hevreh (cognate) — {{hv|lang|peyv}}",
"snippet": "{{hv|LANG|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|peyv}}",
"snippet": "{{mîr|LANG|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|peyv}}",
"snippet": "{{deyn|LANG|…}}"
}
],
"metadata": {
"aa": {
"haswikt": 1,
"sc": [
"Latn",
"Ethi"
]
},
"ab": {
"haswikt": 1,
"sc": [
"Cyrl",
"Latn",
"Geor"
]
},
"aer": {
"sc": "Latn"
},
"af": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ak": {
"haswikt": 1
},
"akk": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Xsux"
},
"als": {
"haswikt": 1
},
"am": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1,
"sc": "Ethi"
},
"an": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ang": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"ar": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"alt": 1,
"haswikt": 1,
"sc": "Arab"
},
"arc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": [
"Hebr",
"Syrc"
]
},
"are": {},
"arz": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"sc": "Arab"
},
"as": {
"haswikt": 1,
"sc": "Beng"
},
"ast": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"av": {
"haswikt": 1
},
"ay": {
"haswikt": 1
},
"az": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl",
"Arab"
]
},
"ba": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"bar": {},
"bat-smg": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"bbl": {
"sc": "Geor"
},
"be": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"be-x-old": {
"sc": "Cyrl"
},
"bg": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"bh": {
"haswikt": 1,
"sc": "Deva"
},
"bhb": {
"sc": "Deva"
},
"bi": {
"haswikt": 1
},
"blt": {
"sc": "Tavt"
},
"bm": {
"haswikt": 1,
"sc": [
"Latn",
"Nkoo",
"Arab"
]
},
"bn": {
"haswikt": 1,
"sc": "Beng"
},
"bo": {
"haswikt": 1,
"sc": "Tibt"
},
"br": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ca": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"cdo": {
"sc": "Hani"
},
"ce": {
"sc": "Cyrl"
},
"ch": {
"haswikt": 1
},
"chr": {
"haswikt": 1,
"sc": "Cher"
},
"cjy": {
"sc": "Hani"
},
"ckb": {
"haswikt": 1,
"sc": "Arab",
"wsc": "ku-Arab"
},
"cmn": {
"sc": "Hani",
"wiktprefix": "zh"
},
"co": {
"haswikt": 1
},
"cpx": {
"sc": "Hani"
},
"cr": {
"haswikt": 1,
"sc": "Cans"
},
"crh": {},
"cs": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"csb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"cu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": [
"Cyrs",
"Glag"
]
},
"cv": {
"sc": "Cyrl"
},
"cy": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"czh": {
"sc": "Hani"
},
"czo": {
"sc": "Hani"
},
"da": {
"g": [
"g",
"nt",
"g-p",
"nt-p",
"p"
],
"haswikt": 1
},
"dax": {},
"de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"dhg": {},
"djb": {},
"dji": {},
"djr": {},
"dng": {
"sc": "Cyrl"
},
"dsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"dsx": {},
"duj": {},
"dv": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Thaa"
},
"dz": {
"haswikt": 1,
"sc": "Tibt"
},
"el": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"en": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"eo": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"es": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"et": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"ett": {
"g": [
"y",
"p"
],
"sc": "Ital"
},
"eu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fa": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-cls": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fa-ira": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"fi": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"fil": {},
"fj": {
"haswikt": 1
},
"fo": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1
},
"fr": {
"g": [
"n",
"m",
"mnmane",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"frm": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fro": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fur": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"fy": {
"g": [
"g",
"nt",
"p"
],
"haswikt": 1
},
"ga": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"gan": {
"sc": "Hani"
},
"gd": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gez": {
"sc": "Ethi"
},
"gl": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"gmw-ecg": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gmy": {
"sc": "Linb"
},
"gn": {
"haswikt": 1
},
"gnn": {
"sc": "Latn"
},
"got": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"sc": "Goth"
},
"grc": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
]
},
"gsw": {
"g": [
"n",
"m",
"nt",
"p"
],
"allowCaps": 1
},
"gu": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Gujr"
},
"guf": {
"sc": "Latn"
},
"gv": {
"haswikt": 1
},
"ha": {
"haswikt": 1
},
"hak": {
"sc": "Hani"
},
"har": {
"sc": "Ethi"
},
"he": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"hi": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Deva"
},
"hif": {
"sc": [
"Latn",
"Deva"
]
},
"hit": {
"sc": "Xsux"
},
"hrx": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"hsb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"hsn": {
"sc": "Hani"
},
"hu": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"hy": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Armn"
},
"ia": {
"haswikt": 1
},
"id": {
"haswikt": 1
},
"ie": {
"haswikt": 1
},
"ik": {
"haswikt": 1
},
"ike": {
"sc": "Cans"
},
"ikt": {
"sc": "Cans"
},
"io": {
"haswikt": 1
},
"is": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"it": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"iu": {
"haswikt": 1,
"sc": "Cans"
},
"ja": {
"haswikt": 1,
"sc": "Jpan"
},
"jay": {
"sc": "Latn"
},
"jbo": {
"haswikt": 1
},
"jv": {
"haswikt": 1
},
"ka": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"khb": {
"sc": [
"Talu",
"Lana",
"Thai"
]
},
"kjh": {
"sc": "Cyrl"
},
"kk": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"kkh": {
"sc": [
"Lana",
"Thai"
]
},
"kl": {
"haswikt": 1
},
"km": {
"haswikt": 1,
"sc": "Khmr"
},
"kn": {
"haswikt": 1,
"sc": "Knda"
},
"ku": {
"g": [
"n",
"m",
"mn",
"n-p",
"m-p",
"p"
],
"wiktprefix": "ku"
},
"ko": {
"haswikt": 1,
"sc": "Kore"
},
"krc": {
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"ks": {
"haswikt": 1,
"sc": [
"Arab",
"Deva"
],
"wsc": "ks-Arab"
},
"kw": {
"haswikt": 1
},
"ky": {
"haswikt": 1,
"g": [
"y",
"p"
],
"sc": "Cyrl"
},
"la": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"lb": {
"g": [
"n",
"m",
"nt",
"p"
],
"haswikt": 1,
"allowCaps": 1
},
"lez": {
"sc": "Cyrl"
},
"li": {
"haswikt": 1
},
"lki": {
"wiktprefix": "ku"
},
"lld": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lmo": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"ln": {
"haswikt": 1
},
"lo": {
"haswikt": 1,
"sc": "Laoo"
},
"lt": {
"alt": 1,
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lv": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"lzz": {
"sc": "Geor"
},
"mg": {
"haswikt": 1
},
"mh": {
"haswikt": 1
},
"mi": {
"g": 0,
"haswikt": 1
},
"mk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ml": {
"haswikt": 1,
"sc": "Mlym"
},
"mn": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": [
"Cyrl",
"Mong"
]
},
"mnp": {
"sc": "Hani"
},
"mo": {
"haswikt": 1,
"sc": "Cyrl"
},
"mol": {
"sc": "Cyrl"
},
"mr": {
"g": [
"n",
"m",
"nt"
],
"haswikt": 1,
"sc": "Deva"
},
"ms": {
"haswikt": 1,
"sc": [
"Latn",
"Arab"
]
},
"mt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"mwp": {
"sc": "Latn"
},
"my": {
"haswikt": 1,
"sc": "Mymr"
},
"na": {
"haswikt": 1
},
"nah": {
"haswikt": 1
},
"nan": {
"wiktprefix": "zh-min-nan",
"sc": "Hani"
},
"nb": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"wiktprefix": "no"
},
"nds-de": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"nds-nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"ne": {
"haswikt": 1,
"sc": "Deva"
},
"nl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nn": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"no": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1
},
"nod": {
"sc": "Lana"
},
"non": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"oc": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"om": {
"haswikt": 1
},
"or": {
"haswikt": 1,
"sc": "Orya"
},
"orv": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrs"
},
"osc": {
"sc": "Ital"
},
"ota": {
"g": [
"y",
"p"
],
"sc": "Arab",
"wsc": "ota-Arab"
},
"pa": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": [
"Guru",
"Arab"
]
},
"pdt": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "nds"
},
"peo": {
"sc": "Xpeo"
},
"phn": {
"sc": "Phnx"
},
"pi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1
},
"pjt": {
"sc": "Latn"
},
"pl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"pms": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"pox": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"împf",
"pf"
]
},
"prs": {
"wiktprefix": "fa",
"sc": "Arab",
"wsc": "fa-Arab"
},
"ps": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ps-Arab"
},
"pt": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1
},
"qu": {
"haswikt": 1
},
"rgn": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"rit": {
"sc": "Latn"
},
"rm": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"rn": {
"haswikt": 1
},
"ro": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"roa-rup": {
"haswikt": 1
},
"ru": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"rue": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"sc": "Cyrl"
},
"ruo": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rup": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"wiktprefix": "roa-rup"
},
"ruq": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"rw": {
"haswikt": 1
},
"sa": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
],
"haswikt": 1,
"sc": "Deva"
},
"sah": {
"sc": "Cyrl"
},
"sc": {
"haswikt": 1
},
"scn": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"sco": {
"sc": "Latn"
},
"sd": {
"haswikt": 1,
"sc": "Arab",
"wsc": "sd-Arab"
},
"sdh": {
"wiktprefix": "ku"
},
"sg": {
"haswikt": 1
},
"sh": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": [
"Latn",
"Cyrl"
]
},
"si": {
"haswikt": 1,
"sc": "Sinh"
},
"simple": {
"haswikt": 1
},
"sk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sl": {
"alt": 1,
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1
},
"sm": {
"haswikt": 1
},
"sn": {
"haswikt": 1
},
"so": {
"haswikt": 1
},
"spx": {
"sc": "Ital"
},
"sq": {
"g": [
"n",
"m"
],
"haswikt": 1
},
"ss": {
"haswikt": 1
},
"st": {
"haswikt": 1
},
"su": {
"haswikt": 1
},
"sux": {
"sc": "Xsux"
},
"sv": {
"g": [
"g",
"nt",
"g-p",
"nt-p"
],
"haswikt": 1
},
"sva": {
"sc": "Geor"
},
"sw": {
"nclass": 1,
"haswikt": 1
},
"syc": {
"sc": "Syrc"
},
"syr": {
"sc": "Syrc"
},
"szl": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
]
},
"ta": {
"haswikt": 1,
"sc": "Taml"
},
"tdd": {
"sc": "Tale"
},
"te": {
"haswikt": 1,
"sc": "Telu"
},
"tg": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Cyrl"
},
"th": {
"haswikt": 1,
"sc": "Thai"
},
"ti": {
"haswikt": 1,
"sc": "Ethi"
},
"tig": {
"sc": "Ethi"
},
"tiw": {
"sc": "Latn"
},
"tk": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tl": {
"haswikt": 1,
"sc": [
"Latn",
"Tglg"
]
},
"tmr": {
"sc": "Hebr"
},
"tn": {
"haswikt": 1
},
"to": {
"haswikt": 1
},
"tpi": {
"haswikt": 1
},
"tr": {
"g": [
"y",
"p"
],
"alt": 1,
"haswikt": 1
},
"ts": {
"haswikt": 1
},
"tt": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"tts": {
"sc": "Thai"
},
"tw": {
"haswikt": 1
},
"udi": {
"sc": [
"Cyrl",
"Latn",
"Armn",
"Geor"
]
},
"ug": {
"g": [
"y",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ug-Arab"
},
"uga": {
"sc": "Ugar"
},
"uk": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p",
"împf",
"pf"
],
"haswikt": 1,
"sc": "Cyrl"
},
"ulk": {
"sc": "Latn"
},
"ur": {
"g": [
"n",
"m",
"n-p",
"m-p",
"p"
],
"haswikt": 1,
"sc": "Arab",
"wsc": "ur-Arab"
},
"uz": {
"g": [
"y",
"p"
],
"haswikt": 1
},
"vec": {
"g": [
"n",
"m",
"n-p",
"m-p"
],
"haswikt": 1
},
"vi": {
"haswikt": 1
},
"vls": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p"
]
},
"vo": {
"haswikt": 1
},
"wa": {
"haswikt": 1
},
"wbp": {
"sc": "Latn"
},
"wo": {
"haswikt": 1
},
"wuu": {
"sc": "Hani"
},
"xae": {
"sc": "Ital"
},
"xcr": {
"sc": "Cari"
},
"xfa": {
"sc": "Ital"
},
"xh": {
"alt": 1,
"nclass": 1,
"haswikt": 1
},
"xlc": {
"sc": "Lyci"
},
"xld": {
"sc": "Lydi"
},
"xlu": {
"sc": "Xsux"
},
"xmf": {
"sc": "Geor"
},
"xno": {
"g": [
"n",
"m",
"n-p",
"m-p"
]
},
"xrr": {
"sc": "Ital"
},
"xst": {
"sc": "Ethi"
},
"xum": {
"sc": "Ital"
},
"xve": {
"sc": "Ital"
},
"xvo": {
"sc": "Ital"
},
"yi": {
"g": [
"n",
"m",
"nt",
"n-p",
"m-p",
"nt-p",
"p"
],
"haswikt": 1,
"sc": "Hebr"
},
"yo": {
"haswikt": 1
},
"yua": {
"g": [
"y",
"p"
],
"alt": 1
},
"yue": {
"sc": "Hani"
},
"za": {
"haswikt": 1,
"sc": "Latn"
},
"zh-classical": {
"sc": "Hani"
},
"zh-min-nan": {
"haswikt": 1
},
"zh-yue": {
"sc": "Hani"
},
"zu": {
"alt": 1,
"nclass": 1,
"haswikt": 1
}
}
}
htz4ghrc7w1r1hve6jk1wokbischilz
Kategorî:Maneyên bêçavkanî
14
1357738
6241651
2026-07-11T18:57:09Z
Wikihez
7344
Rûpel bi "[[Kategorî:Madeyên bêçavkanî|!]]" hat çêkirin
6241651
wikitext
text/x-wiki
[[Kategorî:Madeyên bêçavkanî|!]]
ncob6stlso25vf8z9g7600qotyikdaf
Bikarhêner:Wikihez/skrîpt/js/formatherf.js
2
1357739
6241681
2026-07-11T22:21:46Z
Wikihez
7344
Rûpel bi "/** * Nav: TextTransformGadget * Kar: Guhertina herfên nivîsê (Lowercase, Uppercase, Sentence, Title Case) * Ziman: ku, tr, en */ (function ($) { var messages = { ku: { label: "Format", lowercase: "Hemû herf biçûk (abc)", uppercase: "Hemû herf mezin (ABC)", sentence: "Herfa destpêkê mezin (Abc)", title: "Herfên sernavê (Abc Abc)", select_action: "Guhertina herfan"..." hat çêkirin
6241681
javascript
text/javascript
/**
* Nav: TextTransformGadget
* Kar: Guhertina herfên nivîsê (Lowercase, Uppercase, Sentence, Title Case)
* Ziman: ku, tr, en
*/
(function ($) {
var messages = {
ku: {
label: "Format",
lowercase: "Hemû herf biçûk (abc)",
uppercase: "Hemû herf mezin (ABC)",
sentence: "Herfa destpêkê mezin (Abc)",
title: "Herfên sernavê (Abc Abc)",
select_action: "Guhertina herfan"
},
tr: {
label: "Biçim",
lowercase: "Hepsini küçük yap (abc)",
uppercase: "Hepsini büyük yap (ABC)",
sentence: "Sadece ilk harfi büyük yap (Abc)",
title: "Başlık formatı (Abc Abc)",
select_action: "Harf değişimini seç"
},
en: {
label: "Format",
lowercase: "Lowercase (abc)",
uppercase: "Uppercase (ABC)",
sentence: "Sentence case (Abc)",
title: "Title case (Abc Abc)",
select_action: "Select text transform"
}
};
var userLang = mw.config.get("wgUserLanguage");
var lang = messages[userLang] ? userLang : (messages[userLang.split('-')[0]] ? userLang.split('-')[0] : 'en');
var msg = messages[lang];
// Peyvên ku di "Title Case" de herfên wan nabin mezin
var minorWords = [
"û", "ji", "bi", "de", "di", "li", "re", "ve", "tê", "jî", "jê", "ku", "bo", "ser", "ber", // Kurdî
"ve", "ile", "de", "da", "ki", "mı", "mi", "mu", "mü", "ama", "veya", "için", // Tirkî
"and", "or", "but", "a", "an", "the", "in", "on", "at", "to", "for", "of", "with" // Îngilîzî
];
var transformText = function (text, type) {
if (!text) return text;
switch (type) {
case 'lowercase':
return text.replace(/I/g, 'ı').replace(/İ/g, 'i').toLowerCase();
case 'uppercase':
return text.replace(/i/g, 'İ').replace(/ı/g, 'I').toUpperCase();
case 'sentence':
var first = text.charAt(0);
if (first === 'i') first = 'İ';
else first = first.toUpperCase();
return first + text.slice(1).toLowerCase();
case 'title':
var words = text.split(/\s+/);
var result = words.map(function (word, index) {
var lowerWord = word.toLowerCase();
if (index > 0 && minorWords.indexOf(lowerWord) !== -1) {
return lowerWord;
}
var firstChar = word.charAt(0);
if (firstChar === 'i') firstChar = 'İ';
else firstChar = firstChar.toUpperCase();
return firstChar + word.slice(1).toLowerCase();
});
return result.join(' ');
default:
return text;
}
};
var addTransformTool = function () {
mw.loader.using('ext.wikiEditor', function () {
$('#wpTextbox1').on('wikiEditor-toolbar-buildSection-main', function (evt, section) {
section.groups.insert.tools.texttransform = {
type: 'select',
label: msg.label,
list: {
'lowercase': { label: msg.lowercase },
'uppercase': { label: msg.uppercase },
'sentence': { label: msg.sentence },
'title': { label: msg.title }
},
action: {
type: 'callback',
execute: function (context) {
var type = $(this).data('action').replace('texttransform-', '');
var selection = $("#wpTextbox1").textSelection('getSelection');
if (!selection) return;
var newText = transformText(selection, type);
$("#wpTextbox1").textSelection('encapsulateSelection', {
peri: newText,
replace: true
});
}
}
};
});
});
};
$(document).ready(addTransformTool);
})(jQuery);
aqzmt4g9aw61qlelclt327t9oqsnkil
6241686
6241681
2026-07-11T22:27:22Z
Wikihez
7344
6241686
javascript
text/javascript
(function ($) {
var messages = {
ku: { label: "Format", lowercase: "abc", uppercase: "ABC", sentence: "Abc", title: "Abc Abc" },
tr: { label: "Biçim", lowercase: "abc", uppercase: "ABC", sentence: "Abc", title: "Abc Abc" },
en: { label: "Format", lowercase: "abc", uppercase: "ABC", sentence: "Abc", title: "Abc Abc" }
};
var userLang = mw.config.get("wgUserLanguage");
var lang = messages[userLang] ? userLang : 'ku';
var msg = messages[lang];
var minorWords = ["û", "ji", "bi", "de", "di", "li", "re", "ve", "tê", "jî", "jê", "ku", "bo", "ser", "ber", "and", "or", "the", "in", "of"];
var transformText = function (text, type) {
if (!text) return text;
switch (type) {
case 'lowercase': return text.replace(/I/g, 'ı').replace(/İ/g, 'i').toLowerCase();
case 'uppercase': return text.replace(/i/g, 'İ').replace(/ı/g, 'I').toUpperCase();
case 'sentence': return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
case 'title':
return text.split(/\s+/).map(function (word, index) {
var lower = word.toLowerCase();
if (index > 0 && minorWords.indexOf(lower) !== -1) return lower;
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}).join(' ');
default: return text;
}
};
var applyTransform = function(type) {
var $box = $('#wpTextbox1');
var selection = $box.textSelection('getSelection');
if (selection) {
$box.textSelection('encapsulateSelection', { peri: transformText(selection, type), replace: true });
}
};
// 1. Ji bo Desktop (WikiEditor)
mw.loader.using('ext.wikiEditor', function () {
$('#wpTextbox1').on('wikiEditor-toolbar-buildSection-main', function (evt, section) {
section.groups.insert.tools.texttransform = {
type: 'select', label: msg.label,
list: { 'lowercase': { label: msg.lowercase }, 'uppercase': { label: msg.uppercase }, 'sentence': { label: msg.sentence }, 'title': { label: msg.title } },
action: { type: 'callback', execute: function () { applyTransform($(this).data('action').replace('texttransform-', '')); } }
};
});
});
// 2. Ji bo Mobîl (Menuya hêsan li ser qutîkê)
$(document).ready(function() {
if ($('#wpTextbox1').length && !$('.wikiEditor-ui').length) {
var $mobileTools = $('<div id="mobile-format-tools" style="margin-bottom:5px;"></div>');
$mobileTools.append('<span>' + msg.label + ': </span>');
['lowercase', 'uppercase', 'sentence', 'title'].forEach(function(type) {
var $btn = $('<button type="button" style="margin-right:5px; padding:2px 5px; font-size:12px;">' + msg[type] + '</button>');
$btn.on('click', function(e) { e.preventDefault(); applyTransform(type); });
$mobileTools.append($btn);
});
$('#wpTextbox1').before($mobileTools);
}
});
})(jQuery);
9ok2oj7vwalm9pb13x2mk43syh4ghqn
dîwançe
0
1357740
6241696
2026-07-11T23:23:10Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +ku:navdêr:Dîwana şiîran a biçûk
6241696
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|dîwançe|mê}}
{{navdêr|ku|c=m}}
# [[dîwana|Dîwana]] [[şiîran]] a [[biçûk]].
#: {{jêder|ku|jg=Emê jî li ser şexsiyet û '''dîwançeya''' yek ji van kesan, li ser Mela Ebdullahê Qursincî
bisekinin.|Dîwançeya}}
==== Etîmolojî ====
Ji {{qertaf|ku|dîwan|-çe}}.
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W|tr|divançe}}
{{werger-bin}}
hgqg6mywwbmh64421hb1kv8yli1grti
6241697
6241696
2026-07-11T23:27:25Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241697
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|dîwançe|mê}}
{{navdêr|ku|c=m}}
# [[dîwana|Dîwana]] [[şiîran]] a [[biçûk]].
#: {{jêder-kitêb|ku|jg=Emê jî li ser şexsiyet û '''dîwançeya''' yek ji van kesan, li ser Mela Ebdullahê Qursincî bisekinin.|nivîskar=Mahmut Durmuş|sernav=DÎWANÇEYA MELA EBDULLAHÊ Qursincî (LÊKOLÎN & METN)|sal=2019}}
==== Etîmolojî ====
Ji {{qertaf|ku|dîwan|-çe}}.
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W|tr|divançe}}
{{werger-bin}}
0mqhe9sh5nnrgi3fxecsf1l6itnel7m
6241698
6241697
2026-07-11T23:28:07Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241698
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|dîwançe|mê}}
{{navdêr|ku|c=m}}
# [[dîwana|Dîwana]] [[şiîran]] a [[biçûk]].
#* {{jêder-kitêb|ku|jg=Emê jî li ser şexsiyet û '''dîwançeya''' yek ji van kesan, li ser Mela Ebdullahê Qursincî bisekinin.|nivîskar=Mahmut Durmuş|sernav=DÎWANÇEYA MELA EBDULLAHÊ Qursincî (LÊKOLÎN & METN)|sal=2019}}
==== Etîmolojî ====
Ji {{qertaf|ku|dîwan|-çe}}.
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W|tr|divançe}}
{{werger-bin}}
ate39nzc4qafon9ppj8lc7mjlp9z78j
6241699
6241698
2026-07-11T23:28:30Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241699
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|dîwançe|mê}}
{{navdêr|ku|c=m}}
# {{e|ku|edebiyat|şiîr}} [[dîwana|Dîwana]] [[şiîran]] a [[biçûk]].
#* {{jêder-kitêb|ku|jg=Emê jî li ser şexsiyet û '''dîwançeya''' yek ji van kesan, li ser Mela Ebdullahê Qursincî bisekinin.|nivîskar=Mahmut Durmuş|sernav=DÎWANÇEYA MELA EBDULLAHÊ Qursincî (LÊKOLÎN & METN)|sal=2019}}
==== Etîmolojî ====
Ji {{qertaf|ku|dîwan|-çe}}.
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W|tr|divançe}}
{{werger-bin}}
fee5yzwgj94bs9brlx7breokfyz0cwj
6241709
6241699
2026-07-11T23:48:14Z
Balyozbot
7867
Sererastkirin/rêzkirina şablonên {{[[Şablon:W-|W-]]}}, {{[[Şablon:W+|W+]]}} ([[User:Balyozxane/updateW.py|updateW]])
6241709
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|dîwançe|mê}}
{{navdêr|ku|c=m}}
# {{e|ku|edebiyat|şiîr}} [[dîwana|Dîwana]] [[şiîran]] a [[biçûk]].
#* {{jêder-kitêb|ku|jg=Emê jî li ser şexsiyet û '''dîwançeya''' yek ji van kesan, li ser Mela Ebdullahê Qursincî bisekinin.|nivîskar=Mahmut Durmuş|sernav=DÎWANÇEYA MELA EBDULLAHÊ Qursincî (LÊKOLÎN & METN)|sal=2019}}
==== Etîmolojî ====
Ji {{qertaf|ku|dîwan|-çe}}.
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W+|tr|divançe}}
{{werger-bin}}
57jtjvalgigjbp6cp3rgi4xlwgx22gl
şifêr
0
1357741
6241702
2026-07-11T23:40:49Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +ku:navdêr:
6241702
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{navdêr|ku|c=nt}}
# {{guharto|ku|şofêr}}
314ba0ktz92yx1jjqj1qvql2klcxduw
6241703
6241702
2026-07-11T23:41:02Z
Wikihez
7344
/* Navdêr */
6241703
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{navdêr|ku|c=mn}}
# {{guharto|ku|şofêr}}
avm5iuififfkf86s6j1ecph358gb88i
lînguîstîk
0
1357742
6241711
2026-07-11T23:56:51Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +ku:navdêr:
6241711
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|lînguîstîk|mê}}
{{navdêr|ku|c=m}}
# {{guharto|ku|lenguîstîk}}
bl0acbi1pketrjhv40n4p9z71a30iyr
bursiyer
0
1357743
6241713
2026-07-12T00:14:23Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +ku:navdêr:Telebeyê ku xwedî bursekê ji unîversîte, weqf and dewletekê ye.
6241713
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{navdêr|ku|c=nt}}
# [[Telebeyê]] ku [[xwedî]] [[burs]]ekê [[ji]] [[unîversîte]], [[weqf]] [[an]] [[dewlet]]ekê ye.
#* {{bênimûne|ku}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W|en|scholar}}, {{W|en|scholarship holder}}
* {{Z|tr}}: {{W|tr|bursiyer}}
{{werger-bin}}
tutz3mbemm7lsnm30uktrf623ti7xc0
6241714
6241713
2026-07-12T00:15:00Z
Wikihez
7344
/* Navdêr */
6241714
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|bursiyer|mê û nêr}}
{{navdêr|ku|c=mn}}
# [[telebe|Telebeyê]] ku [[xwedî]] [[burs]]ekê [[ji]] [[unîversîte]], [[weqf]] [[an]] [[dewlet]]ekê ye.
#* {{bênimûne|ku}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W|en|scholar}}, {{W|en|scholarship holder}}
* {{Z|tr}}: {{W|tr|bursiyer}}
{{werger-bin}}
bpyx1t9jjihzs2uzl3270tqt28stowu
6241717
6241714
2026-07-12T00:17:53Z
Wikihez
7344
[[Bikarhêner:Wikihez/wergerîne.js|Wergerîne]] ji [[en:scholarship holder]]
6241717
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|bursiyer|mê û nêr}}
{{navdêr|ku|c=mn}}
# [[telebe|Telebeyê]] ku [[xwedî]] [[burs]]ekê [[ji]] [[unîversîte]], [[weqf]] [[an]] [[dewlet]]ekê ye.
#* {{bênimûne|ku}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|fr}}: {{W+|fr|boursier|}}
* {{Z|en}}: {{W+|en|scholarship holder}} {{W+|en|scholar}}
* {{Z|pt}}: {{W-|pt|bolsista|}}
* {{Z|es}}: {{W+|es|becario|}}, {{W+|es|becado|}}
* {{Z|tr}}: {{W-|tr|bursiyer}}
{{werger-bin}}
:{{werger çavkanî|en|scholarship holder|beş=Ev qismê Wergerê|oldid=91120755}}
tjm6byp1ixp5yfngrwf0glelqcyhjza
6241718
6241717
2026-07-12T00:18:15Z
Wikihez
7344
Werger: sernav: "kesê ku burs werdigire" (bi alîkarî)
6241718
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|bursiyer|mê û nêr}}
{{navdêr|ku|c=mn}}
# [[telebe|Telebeyê]] ku [[xwedî]] [[burs]]ekê [[ji]] [[unîversîte]], [[weqf]] [[an]] [[dewlet]]ekê ye.
#* {{bênimûne|ku}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser|kesê ku burs werdigire}}
* {{Z|fr}}: {{W+|fr|boursier|}}
* {{Z|en}}: {{W+|en|scholarship holder}} {{W+|en|scholar}}
* {{Z|pt}}: {{W-|pt|bolsista|}}
* {{Z|es}}: {{W+|es|becario|}}, {{W+|es|becado|}}
* {{Z|tr}}: {{W-|tr|bursiyer}}
{{werger-bin}}
:{{werger çavkanî|en|scholarship holder|beş=Ev qismê Wergerê|oldid=91120755}}
dxra8q8e1y3xpmtdv7zr4tm51nelpwk
6241722
6241718
2026-07-12T00:59:20Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241722
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|bursiyer|mê û nêr}}
{{navdêr|ku|c=mn}}
# [[telebe|Telebeyê]] ku [[xwedî]] [[burs]]ekê [[ji]] [[unîversîte]], [[weqf]] [[an]] [[dewlet]]ekê ye.
#* {{bênimûne|ku}}
==== Etîmolojî ====
Ji {{ji|fr|ku|boursier}}.
==== Werger ====
{{werger-ser|kesê ku burs werdigire}}
* {{Z|fr}}: {{W+|fr|boursier|}}
* {{Z|en}}: {{W+|en|scholarship holder}} {{W+|en|scholar}}
* {{Z|pt}}: {{W-|pt|bolsista|}}
* {{Z|es}}: {{W+|es|becario|}}, {{W+|es|becado|}}
* {{Z|tr}}: {{W-|tr|bursiyer}}
{{werger-bin}}
:{{werger çavkanî|en|scholarship holder|beş=Ev qismê Wergerê|oldid=91120755}}
au3i2du6zy7z95zh3mjhtsdpfymyey5
scholarship holder
0
1357744
6241715
2026-07-12T00:15:24Z
Wikihez
7344
([[Bikarhêner:Wikihez/newentrywiz.js|NEC]]) +en:navdêr: Bi [[Bikarhêner:Wikihez/CreateTranslation.js|amûrê]] ji wergerên [[bursiyer]]:
6241715
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{en-navdêr}}
# [[bursiyer]]
18i2e4yx1b3mj7q6qm21nd9lw6tb36a
6241716
6241715
2026-07-12T00:16:00Z
Wikihez
7344
/* {{ziman|en}} */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:scholarship holder|en.wikt]]
6241716
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{en-navdêr}}
# [[bursiyer]]
#: {{hevmane|en||scholarship recipient|grant recipient|grant holder|scholarship beneficiary|grantee}}
==== Têkildar ====
* {{g|en|scholar}}
* {{g|en|scholarly}}
* {{g|en|scholarship}}
h1m3daii9he06du9c69iravb8xk74bg
Şablon:koordîne
10
1357745
6241727
2026-07-12T10:08:20Z
Wikihez
7344
Ji bo [[Şablon:termên koordîne]] hat beralîkirin
6241727
wikitext
text/x-wiki
#BERALÎKIRIN [[Şablon:termên koordîne]]
3226zx2ohrzwyf0dpo3d1063hut8942
Gotûbêja bikarhêner:Kewkûrk
3
1357746
6241750
2026-07-12T11:56:11Z
Wikihez
7344
xêrhatin lê zêde kir
6241750
wikitext
text/x-wiki
{{bixêrhatin}}
== Xêrhatin ==
Merheba bikarhênera/ê me ya/ê hêja: ''Kewkûrk'',
Bi xêr hatî ferhenga kurdî-kurdî WÎKÎFERHENGê {{=)}}
Em hêvîdar in ku tu jî di avakirina vê ferhengê de alîkariya me bikî.
Eger pirsên te hebin, dikarî li ser [[WF:Dîwan]]ê bipirsî.
Xebatxweş.
:—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:56, 12 tîrmeh 2026 (UTC)
:Not: Min guhartina te ya Alîkarî:Nivîsin betal kir ji ber ku ev cih xelet e. Divê li [[dêrtin]] binivîsî.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:56, 12 tîrmeh 2026 (UTC)
ov3xkpbyi7ydw31trtv6mreodiinwce
6241751
6241750
2026-07-12T11:57:23Z
Kewkûrk
15130
/* Xêrhatin */ Bersiv
6241751
wikitext
text/x-wiki
{{bixêrhatin}}
== Xêrhatin ==
Merheba bikarhênera/ê me ya/ê hêja: ''Kewkûrk'',
Bi xêr hatî ferhenga kurdî-kurdî WÎKÎFERHENGê {{=)}}
Em hêvîdar in ku tu jî di avakirina vê ferhengê de alîkariya me bikî.
Eger pirsên te hebin, dikarî li ser [[WF:Dîwan]]ê bipirsî.
Xebatxweş.
:—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:56, 12 tîrmeh 2026 (UTC)
:Not: Min guhartina te ya Alîkarî:Nivîsin betal kir ji ber ku ev cih xelet e. Divê li [[dêrtin]] binivîsî.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:56, 12 tîrmeh 2026 (UTC)
::spas bira,min xeletî kir. Ez lêborînê dixwazim. [[Bikarhêner:Kewkûrk|Kewkûrk]] ([[Gotûbêja bikarhêner:Kewkûrk#top|gotûbêj]]) 11:57, 12 tîrmeh 2026 (UTC)
ffrmmgjd2ifj0g255zl4c17fc1no1y9