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
Alîkarî:Bikaranîna şablonan
12
3093
6241906
6105142
2026-07-12T21:51:13Z
Wikihez
7344
6241906
wikitext
text/x-wiki
{{guherrandin}}
'''Şablon''' gotareke bi kodên wîkîyê yên taybet (Şablon:-navê şablonê-) in ku destûr dide heman agahî di gelek rûpelên din de bên dubarekirin.
Avantaja şablonan ev e ku dema şablon bixwe tê guherandin, hemû rûpelên ku bi wê şablonê re girêdayî ne jî dê bi otomatîkî bên guherandin. Herwiha bikaranîna [[:kategorî:!Serkategorî|kategoriyan]] jî hêsantir dibe. Ku şablon bên bikaranîn, rûpel jixweber dikevin kategoriyên rast.
Di Wîkîferhengê de gelek şablon tên bikaranîn. Loma ku hûn hînî bikaranîna wan bibin, karê we dê hesantir bibe. Hûn dikarin hemû şablonan di [[:Kategorî:Şablon]] bibînin.
== Çawa? ==
Bi du awayî şablon tê lêzêdekirin. Di awayê yekem de li bişkoka [[pazil]]ê [[Wêne:OOjs UI icon puzzle-ltr.svg|Insert a Template]] bitikinîn û li şablona ku hûn dixwazin bi kar bînin bigerin. Piştre, şablona xwe ji encaman hilbijêrin. Dûre weke ku di wêneya duyem de parametreyên xwe binivîsîn.
[[Wêne:Adding a template ku.wikt.png|500px]]
[[Wêne:Insert a Template ku.wikt.png|500px]]
Di awayê duyem de hûn dikarin bixwe şablona ku dixwazin bi kar bînin binivîsîn. Misalen heger <code>'''{{şx|f|ku|mecazî}}'''</code> binivîsî jî, bi otomatîkî <code>{{f|ku|mecazî}}</code> derdikeve. Şablona '''{{şx|etîket}}''' (bi kurtî {{şx|e}}) ji bo nîşandana etîketên peyvan tê bikaranîn. Ji bo zimanên din li şûna <code>'''ku'''</code> koda zimanî binivîsin. ''Ji bo kodên zimanên din binêre'': [[WF:LZ|Lîsteya zimanan]]
Hemû rûpelên bi şablona <code>'''{{şx|f|ku|mecazî}}'''</code> dikevin rûpela '''[[:Kategorî:Mecazî bi kurmancî]]'''.
== Şablonên sereke yên gotaran ==
Ji şablonên sereke yên gotaran binêre: [[Alîkarî:Rêziman]] / [[Şablon:navdêr#Bikaranîn]] / [[Şablon:lêker#Bikaranîn]] ({{şl|Lîsteya şablonên rêzimanê}}) + [[Wîkîferheng:Format]] / [[Wîkîferheng:Peyvekê çêke]]
== Şablon li gorî kategoriyên peyvan ==
Etîketên li jêr bi riya şablona {{ş|etîket}} (bi kurtî {{ş|f}}) tê bikaranîn. Ji bo çêkirina etîketên nû binêrin belgekirina Modula [[Modul:ferhengok]]
{{#invoke:labels doc|show}}
== Li gorî rewşa peyvan ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Kategorî !! Têbînî
|-
| {{ş|devkî}}
|{{şx|devkî|ku}}
| {{devkî|ku}}
| [[:Kategorî:Devkî]]
| Ji bo peyvên devokî.
|-
| {{ş|kevnbûyî}}
| {{şx|kevnbûyî|en|abode}}
| {{kevnbûyî|en|abode}}
| [[:Kategorî:Formên kevnbûyî]]
| Ji bo peyvên kevnbûyî tê bikaranîn. Mîsalen peyva bi îngilîzî ya "[[justifie]]".
|-
| {{ş|sormancî}}
| {{şx|sormancî}}
| {{sormancî}}
| [[:Kategorî:Sormancî]]
| Ji bo peyvên [[sormancî]] tê bikaranîn.
|-
| {{ş|tirkmancî}}
| {{şx|tirkmancî}}
| {{tirkmancî}}
| [[:Kategorî:Tirkmancî]]
| Ji bo peyvên [[tirkmancî]] tê bikaranîn.
|-
| {{ş|guherto}}
| {{şx|guherto|well wisher}}
| {{guherto|well wisher}}
|
| Ji bo awayên din ên peyvan tê bikaranîn. Mîsalen peyva bi îngilîzî ya "[[well wisher]]".
|-
| {{ş|guherto}}
| {{şx|guherto|kêlî|beş=Navdêr 2}}
| {{guherto|kêlî|beş=Navdêr 2}}
|
| Di şablona "guherto" de ger peyveke pir-beşî hebe, yanî peyvek him navdêr, him lêker be, an xwedî du maneya navdêrî be mirov bixwaze tenê ber bi yek ji wan awayan ve alî bike <code><nowiki>{{guherto|kêlî|beş=Navdêr 2}}</nowiki></code> an "|beş=Rengdêr 2" hwd. tê bikaranîn. Ji bo nimûneyekî binêre "[[kêlik]]".
|-
| {{ş|awayekî din}}
| {{şx|awayekî din|en|gate crasher}}
| {{awayekî din|en|gate crasher}}
|
| Ji bo awayên din ên peyvan / formên alternatîv tê bikaranîn. Mîsalen peyva bi îngilîzî ya "[[gate crasher]]". Herwiha ji bo nivîsîna erebî/latînîkirina peyvan jî tên bikaranîn. mînak [[جودا]], [[yushutsunyū]]
|-
| {{ş|onomatopoetîk}} an {{ş|onp}}
| {{şx|onomatopoetîk|ku}} an {{şx|onp|ku}}
| {{onomatopoetîk|ku}}
| [[:Kategorî:Dengên siriştî bi kurmancî]]
| Ji bo peyvên onomatopoetîk mîna [[kuxik]], [[xulexul]], [[xuşexuş]].
|-
|}
== Li gorî devokên kurmancî ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Kategorî !! Têbînî
|-
| {{ş|dever|}}
| {{şx|dever|Aldûş}}
| {{dever|Aldûş}}
| [[:Kategorî:Peyvên kurmancî ji Aldûşê]]
| Ji bo nîşankirina [[dever]] an [[herêm]]a peyvan. kurtkirin {{şx|dever|Aldûş}}
|-
| {{ş|badînî}}
|{{şx|badînî}}
| {{badînî}}
| [[:Kategorî:Badînî]]
|Ji bo peyvên bi devoka [[badînî]] an [[behdînanî]].
|-
| {{ş|botî}}
|{{şx|botî}}
| {{botî}}
| [[:Kategorî:Botî]]
|Ji bo peyvên bi devoka [[botî]], [[botanî]] an jî [[boxtî]]
|-
| {{ş|goyî}}
|{{şx|goyî}}
| {{goyî}}
| [[:Kategorî:Goyî]]
|Ji bo peyvên bi devoka [[goyî]] an [[goyanî]].
|-
| {{ş|reşî}}
|{{şx|reşî}}
| {{reşî}}
| [[:Kategorî:Reşî]]
|Ji bo peyvên bi devoka [[reşî]] an [[reşwanî]].
|-
| {{ş|serhedî}}
|{{şx|serhedî}}
| {{serhedî}}
| [[:Kategorî:Serhedî]]
|Ji bo peyvên bi devoka [[serhedî]] an [[serhedkî]].
|-
| {{ş|sînemilî}}
|{{şx|sînemilî}}
| {{sînemilî}}
| [[:Kategorî:Sînemilî]]
|Ji bo peyvên bi devoka [[sînemilî]].
|}
== Şablonên ji bo wîkîpediyayê ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Têbînî
|-
| {{ş|w}}
|{{şx|w|Mehmed Uzun}}
| {{w|Mehmed Uzun}}
| Ji bo lînkkirina wîkîpediyayê. Hûn dikarin vê şablonê bi jêderan bi kar bînin.
|-
| {{ş|wp}}
|{{şx|wp|piling}} yan <br>{{şx|wp|ziman{{=}}en|Sten gun}}
| {{wp|piling}} <br>{{wp|ziman=en|Sten gun}}
| Ji bo lînkkirina gotarê ji wîkîpediyayê re.
|-
| {{ş|wpedî}}
|{{şx|wpedî|piling}} yan <br> {{şx|wpedî|ziman{{=}}en|Sten gun}}
| {{wpedî|piling}} <br>{{wpedî|ziman=en|Sten gun}}
| Ji bo lînkkirina gotarê ji Wîkîpediyayê re di beşa <code><nowiki>==== Binêre herwiha ====</nowiki></code> de.
|}
== Ji bo fonetîkê ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Kategorî !! Têbînî
|-
| rowspan="6" | {{ş|bilêv}}
|{{şx|bilêv|k|nerm}}
| {{bilêv|k|nerm}}
| [[:Kategorî:Bilêvkirinên kurmancî bi k-ya nerm]]
| ''Ji bo peyvên bi k-ya nerm.''
|-
|{{şx|bilêv|k|req}}
| {{bilêv|k|req}}
| [[:Kategorî:Bilêvkirinên kurmancî bi k-ya req]]
| ''Ji bo peyvên bi k-ya req.''
|-
|{{şx|bilêv|p|nerm}}
| {{bilêv|p|nerm}}
| [[:Kategorî:Bilêvkirinên kurmancî bi p-ya nerm]]
| ''Ji bo peyvên bi p-ya nerm.''
|-
|{{şx|bilêv|p|req}}
| {{bilêv|p|req}}
| [[:Kategorî:Bilêvkirinên kurmancî bi p-ya req]]
| ''Ji bo peyvên bi p-ya req.''
|-
|{{şx|bilêv|r|qelew}}
| {{bilêv|r|qelew}}
| [[:Kategorî:Bilêvkirinên kurmancî bi r-ya qelew]]
| ''Ji bo peyvên bi r-ya qelew.''
|-
|{{şx|bilêv|r|zirav}}
| {{bilêv|r|zirav}}
| [[:Kategorî:Bilêvkirinên kurmancî bi r-ya zirav]]
| ''Ji bo peyvên bi r-ya zirav.''
|}
== Ji bo tewandinê ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Têbînî
|-
| {{ş|ku-tewîn-nav}}
|
* {{şx|ku-tewîn-nav|peyv|mê}}
* {{şx|ku-tewîn-nav|kar|nêr}}
|
* bo mînaka mê bnr: [[peyv]]
* bo mînaka nêr bnr: [[kar]]
| Ji bo ji bo tewandinê [[navdêr]]an. Ji bo agahiyên berfirehtir bnr. {{ş|ku-tewîn-nav}}
|-
| {{ş|ku-tewîn-rd}}
|{{şx|ku-tewîn-rd|rind}}
| bo mînakê bnr: [[rind]]
| Ji bo tewandina [[rengdêr]]an. Ji bo agahiyên berfirehtir bnr. {{ş|ku-tewîn-rd}}
|-
| {{ş|ku-tewîn-lk}}
|{{şx|ku-tewîn-lk|helîn|form{{=}}negerguhêz|niha{{=}}hel|borî{{=}}helî|borî2{{=}}heliya}}
| bo mînakê bnr: [[helîn]]
| Ji bo tewandina [[lêker]]an. Tenê li ser gotaran tên bikaranîn. Dema niha û dema borî nîşan dide. Ji bo agahiyên berfirehtir bnr. {{ş|ku-tewîn-lk}}
|-
| {{ş|ku-tewandin}}
|{{şx|ku-tewandin|helîn|form{{=}}negerguhêz|niha{{=}}hel|borî{{=}}helî|borî2{{=}}heliya}}
| bo mînakê bnr: [[Tewandin:helîn]]
| Ji bo tewandina [[lêker]]an. Hemû tewandinên lêkerê tên nişandan. Ji bo agahiyên berfirehtir bnr. {{ş|ku-tewandin}}
|}
== Ji bo beşa Wergerê ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Têbînî
|-
| {{ş|werger-ser}}
|| {{şx|werger-ser|sernav|hejmara wateyê|stûn=}}
||
|| Piştî <nowiki>==== Werger ====</nowiki>ê bi kar bînin. Ji bo taybetmendiyên şablonê bnr. {{ş|werger-ser}}.
|-
| {{ş|Z}}
|| {{şx|Z|en}}
|| {{Z|en}}
||Piştî Z-yê, koda zimên bi kar bînin. Ji bo taybetmendiyên şablonê bnr. {{ş|Z}}.
|-
| {{ş|W}}
||
* {{şx|W|en|book}}
* {{şx|W|koda zimanê|peyv|zayend|jimar|tr{{=}}transliterasyon|cuda{{=}}|guman{{=}}}}
|| {{W|en|book}}
|| Ji bo taybetmendiyên şablonê bnr. {{ş|W}}.
|-
| {{ş|W+}}
|| {{şx|W+|en|book}}
|| {{W+|en|book}}
|| Ji bo taybetmendiyên şablonê bnr. {{ş|W+}}.
|-
| {{ş|W-}}
|| {{şx|W-|en|book}}
|| {{W-|en|book}}
|| Ji bo taybetmendiyên şablonê bnr. {{ş|W-}}.
|-
| {{ş|werger-bin}}
||
||
|| Ji bo taybetmendiyên şablonê bnr. {{ş|werger-bin}}.
|}
== Ji bo beşa Etîmolojî ==
{{bnr-h|Wîkîferheng:Etîmolojî}}
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Kategorî !! Têbînî
|-
| {{ş|ji}}<br/>
----
{{ş|ji}} + {{ş|g}}
| {{şx|ji|ar|ku|جاسوس|tr{{=}}jāsūs}}<br/>
----
{{şx|ji|ar|ku|-}} {{şx|g|ar|جاسوس|cuda{{=}}جَاسُوس|tr{{=}}jāsūs}}
| {{ji|ar|ku|جاسوس|tr=jāsūs}}<br/>
----
{{ji|ar|ku|جاسوس|cuda=جَاسُوس|tr=jāsūs}}
| [[:Kategorî:Peyvên kurmancî ji erebî]] û [[:Kategorî:Peyvên ji erebî]]
| Ji bo taybetmendiyên şablonê bnr. {{ş|ji}} û {{ş|g}}.
|-
| {{ş|ji-}}
|
|
|
| Wekî şablona {{ş|ji}} tê bikaranîn lê belê li vir '''nivîsa zimên''' dernakeve. Ji bo taybetmendiyên şablonê bnr. {{ş|ji-}}.
|-
| {{ş|pêk}}
| {{şx|pêk|ku|agir|best|ji2{{=}}bestin}}
| ''[[agir]] + [[best]]'' "([[bestin]])".
| [[:Kategorî:Peyvên pêkhatî bi kurmancî|Peyvên pêkhatî bi kurmancî]]
| Tenê ji bo peyvên '''pêkhatî'''.
|-
| {{ş|pêş}}
| {{şx|pêş|ku|bê-|por}}
| ''[[bê-]] + [[por]]''.
| [[:Kategorî:Peyvên kurmancî bi pêşgira bê-|Peyvên kurmancî bi pêşgira bê-]]
| Tenê ji bo peyvên pêkhatî yên bi '''[[pêşgir]]an''' pêk tê.
|-
| {{ş|paş}}
| {{şx|paş|ku|rojname|-van}}
| ''[[rojname]] + [[-van]]''.
| [[:Kategorî:Peyvên kurmancî bi paşgira -van|Peyvên kurmancî bi paşgira -van]]
| Tenê ji bo peyvên pêkhatî yên bi '''[[paşgir]]an''' pêk tê.
|-
| {{ş|navg}}
| {{şx|navg|ku|rast|-e-|rast}}
| ''[[rast]] + [[-e-]] + [[rast]]''.
| [[:Kategorî:Peyvên kurmancî bi navgira -e-|Peyvên kurmancî bi navgira -e-]]
| Tenê ji bo peyvên pêkhatî yên bi '''[[navgir]]an''' pêk tê
|}
== Ji bo jêgirtinan ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Têbînî
|-
| {{ş|jêder}}
|{{şx|jêder|ku|Mustefa Aydogan: ''Şivanê Kurmanca ya Erebê Şemo - I -'', Kurmancî, Hj. 45, 2009, r. 1|jêgirtin=Jêgirtinek}}
| {{jêder|ku|Mustefa Aydogan: ''Şivanê Kurmanca ya Erebê Şemo - I -'', Kurmancî, Hj. 45, 2009, r. 1|jêgirtin=Jêgirtinek}}
| Ji bo jêgirtinên gelemperî li gel mînakê.
|-
| {{ş|jêder-pirtûk}}
| <syntaxhighlight lang="wikitext">{{jêder-pirtûk|ku|jêgirtin=Jêgirtinek|nivîskar=Mihemed Şarman|sernav=Pirça Winda|cîh=Stembol<br>
|weşanxane={{w|Weşanên Avesta|Avesta}}|sal=2016|çap=2|rûpel=76|isbn=978-605-5585-41-9}}</syntaxhighlight>
| {{jêder-pirtûk|ku|jêgirtin=Jêgirtinek|nivîskar=Mihemed Şarman|sernav=Pirça Winda|cîh=Stembol<br>
|weşanxane={{w|Weşanên Avesta|Avesta}}|sal=2016|çap=2|rûpel=76|isbn=978-605-5585-41-9}}
| Ji bo jêgirtinên ji pirtûkan li gel mînakê.
|-
| {{ş|jêder-kovar}}
| <syntaxhighlight lang="wikitext">{{jêder-kovar|ku|jêgirtin=Jêgirtinek|kovar=Kovara Kurmancî|sernav=Masî û masîvanî|url=https://www.institutkurde.org/publications/kurmanci/telechargement/ku50.pdf<br>
|nivîskar=Eyûb Sînan KIRAN|weşanxane=Weşanên Enstîtuya Kurdî ya Parîsê|hejmar=50|sal=Havîn 2012|rûpel=4|ziman=ku}}</syntaxhighlight>
| {{jêder-kovar|ku|jêgirtin=Jêgirtinek|kovar=Kovara Kurmancî|sernav=Masî û masîvanî|url=https://www.institutkurde.org/publications/kurmanci/telechargement/ku50.pdf|nivîskar=Eyûb Sînan KIRAN|weşanxane=Weşanên Enstîtuya Kurdî ya Parîsê|hejmar=50|sal=Havîn 2012|rûpel=4|ziman=ku}}
| Ji bo jêgirtinên ji kovaran li gel mînakê.
|-
| {{ş|jêder-malper}}
|<syntaxhighlight lang="wikitext">{{jêder-malper|ku|jêgirtin=Jêgirtinek|nivîskar=DENÎZ ÎKE|sernav=Şano sînoran ji holê radike|url=https://yeniozgurpolitika.net/sano-sinoran-ji-hole-radike/|malper=yeniozgurpolitika.net|dîrok=17.01.2020}}</syntaxhighlight>
| {{jêder-malper|ku|jêgirtin=Jêgirtinek|nivîskar=DENÎZ ÎKE|sernav=Şano sînoran ji holê radike|url=https://yeniozgurpolitika.net/sano-sinoran-ji-hole-radike/|malper=yeniozgurpolitika.net|dîrok=17.01.2020}}
| Ji bo jêgirtinên ji malperên înternetê li gel mînakê. '''Piştî çêkirina şablonê, ji kerema xwe re li ser arşîvê bitikînin û jêgirtinê li ser archive.org-ê jî qeyd bikin.'''
|-
| {{ş|pirtûk}}
|<syntaxhighlight lang="wikitext">{{pirtûk|ku|nivîskar={{w|Mihemed Şarman}}|sernav=Pirça Winda|cîh=Stembol<br>
|weşanxane={{w|Weşanên Avesta|Avesta}}|sal=2016|çap=2|rûpel=76|isbn=978-605-5585-41-9}}</syntaxhighlight>
| {{pirtûk|ku|jêgirtin=Jêgirtinek|nivîskar={{w|Mihemed Şarman}}|sernav=Pirça Winda|cîh=Stembol|weşanxane={{w|Weşanên Avesta|Avesta}}<br>
|sal=2016|çap=2|rûpel=76|isbn=978-605-5585-41-9}}
| Ji bo çavkaniyên pirtûkan di bin beşa <nowiki>=== Çavkanî ===</nowiki> de.
|-
| {{ş|malper}}
|<syntaxhighlight lang="wikitext">{{malper|nivîskar=DENÎZ ÎKE|sernav=Şano sînoran ji holê radike|url=https://yeniozgurpolitika.net/sano-sinoran-ji-hole-radike/|malper=yeniozgurpolitika.net|dîrok=17.01.2020}}</syntaxhighlight>
| {{malper|jêgirtin=Jêgirtinek|nivîskar=DENÎZ ÎKE|sernav=Şano sînoran ji holê radike|url=https://yeniozgurpolitika.net/sano-sinoran-ji-hole-radike/|malper=yeniozgurpolitika.net|dîrok=17.01.2020}}
| Ji bo çavkaniyên ji malperên înternetê di bin beşa <nowiki>=== Çavkanî ===</nowiki> de. '''Piştî çêkirina şablonê, ji kerema xwe re li ser arşîvê bitikînin û jêgirtinê li ser archive.org-ê jî qeyd bikin.'''
|}
== Şablonên din ==
{| class="wikitable sortable"
|-
! Navê şablonê !! Bikaranîn !! Encam !! Têbînî
|-
| {{ş|ş}}
|{{şx|ş|jêder}}
| {{ş|jêder}}
| Ji bo ''nîşankirina'' şablonan li ser gotûbêjan wek mînakekê an jî ji bo lînkkirina koda şablonan.
|-
| {{ş|şx}}
|{{şx|şx|jêder}}
| {{şx|jêder}}
| Ji bo nîşankirina ''bikaranîna'' şablonan li ser gotûbêjan wek mînakekê.
|-
| {{ş|ku-IPA}}
|{{şx|ku-IPA|şixulandin}}
| {{ku-IPA|şixulandin}}
| Ji bo bilêvkirin / telafûzên peyvên kurmancî.
|-
| {{ş|ku-tîp}}
|{{şx|ku-tîp|spîdmît}}
| {{ku-tîp|spîdmît}}
| Ji bo bilêvkirina peyvên biyanî ya bi tîpên kurmancî. Bo mînak bnr. [[speedmeet]]
|-
| {{ş|kîte}}
|{{şx|kîte|ku|Kur|dis|tan}}
| {{kîte|ku|Kur|dis|tan}}
| Ji bo kîtekirina peyvan.
|-
| {{ş|babîl}}
|
|
| Ji bo rûpela bikarhêneran. Ji bo taybetmendiyan bnr. {{ş|babîl}}
|-
| {{ş|ragihandin}}
|
{{şx|ragihandin|Mînak}}
an
{{şx|r|Mînak}}
| {{ragihandin|Mînak}} an {{r|Mînak}}
| Li ser gotûbêjan tê bikaranîn. Dema dixwazî yekî di gotûbêjê de etîket û agahdar bikî divê bên bikaranîn. Ji bo taybetmendiyan bnr. {{ş|ragihandin}}
|-
| {{ş|silav|}}
| {{şx|silav|Mînak}}
| {{silav|Mînak}}
| Li ser gotûbêjan tê bikaranîn. Dema dixwazî yekî di gotûbêjê de etîket û agahdar bikî dikarî li şûna {{ş|ragihandin }}bi kar bînî. Ji bo taybetmendiyan bnr. {{ş|silav}}
|-
| [[hiyeroglîf]]
| <nowiki>{{navdêr|egy|<hiero>z:z-m-E6</hiero>}}</nowiki>
| <code>{{navdêr|egy|<hiero>z:z-m-E6</hiero>}}</code>
| Hiyeroglîfên bi zimanê [[misrî]] bi vî awayî tên nivîsîn. Şablona wê ya xweser tune ye. Li şûna <code>nav</code> [[Alîkarî:Cureyên peyvan|cureya peyvê]] binivîsin. Mînak: '''[[zn]]'''
|-
| {{ş|ku-Arab}}
| {{şx|ku-Arab|[[کورد]]}}
| {{ku-Arab|[[کورد]]}}
| Ji bo alfabeya kurmancî ya bi tîpên erebî divê vê şablonê bê bikaranîn.
|-
| {{ş|ku-Arab-translit}}
| {{şx|ku-Arab-translit|ئەمریکا دوو لیوایێن پێشمەرگەی پرچەک دکەت}}
| {{ku-Arab-translit|ئەمریکا دوو لیوایێن پێشمەرگەی پرچەک دکەت}}
| Ji bo [[transkrîpsiyon]]a peyv an hevokên bi alfabeya kurmancî ya bi tîpên erebî tê bikaranîn.
|-
| {{ş|ds}}
| {{şx|ds|bikarîner|bikarhêner}}
| {{ds|bikarîner|bikarhêner}}
| Ji bo standardkirina peyvan / têgihan tê bikaranîn. Ger peyvek bi du an zêdetir formatan wek forma standard hatibe qeydkirin ev format li her formateke peyvê tê tevlîkirin ji bo ku were standardkirin. Nimûne: peyvên "bikarîner", "bikarhêner". Li ser Wîkîkferhengê her formateke peyvan cih digirin. Lê yek ji wan wek standard , yên din wek versiyon tên qeydkirin. Ji bo peyvên "bikarîner", "bikarhêner" wek standard "bikarîner" were bijartin, li ser rûpela din li beşa maneyê "''Guhertoyeke'' [[bikarîner]]" tê xuyan (bi bikaranîna şablona "guherto", awayê bikaranîna wê li jor hatiye nîşandan). Lê li ser beşa maneyê yê peyva standard, maneya peyvê bi detay tê îzahkirin.
|-
| {{ş|mj|}}
| {{şx|mj|kêmpeyda}}
| {{mj|kêmpeyda}}
| Ji bo mijarên ku şablon nehatine çêkirin Ji bo nimûneyekî bnr. ''"[[spammable]]"''.
|-
| {{ş|MongolîUnicode}}
| {{şx|MongolîUnicode|ᠤᠯᠠᠭᠠᠨ}}
| {{MongolîUnicode|ᠤᠯᠠᠭᠠᠨ}}
| Ji bo peyvên mongolî mînak '''[[ᠤᠯᠠᠭᠠᠨ]]'''.
|}
[[Kategorî:Alîkarî]]
i3ej90x4s4ynglyzyduxku4rodtco42
rast
0
3430
6241934
6237155
2026-07-12T23:24:12Z
Wikihez
7344
/* Dijmane */
6241934
wikitext
text/x-wiki
{{bnr-h|Rast}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-rast.wav|Deng|dever=Bidlîs}}
* {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-rast.wav|Deng|Bidlîs}}
=== Rengdêr ===
{{ku-tewîn-rd|rast}}
[[Wêne:Westminster_cavalry.jpg|thumb|Şûr di destê rastê yê siwarekî de. (4)]]
[[Wêne:HumanHand.JPG|thumb|Destekî '''rast'''. (4)]]
{{rengdêr|ku}}, {{r-ya req}}, {{t-ya nerm}}
# [[bêxeletî]], [[bêşaşî]], [[bêkêmasî]], ne [[şaş]], ne [[çewt]], ne [[xelet]]
#: ''Bersiva te '''rast''' e.''
# ne [[derew]], ne [[virr]]:
#: ''Ew '''rast''' dibêje.''
# ne [[xwehr]], ne [[xwahr]]:
#: ''xeteke '''rast''', rêyeke '''rast''' ''
#: ''Ev darê di destê min de '''rast''' e.''
# [[rex]]ê [[dijber]]î rexê [[çep]]ê
#: ''destê '''rast''', aliyê '''rast''' ''
#: {{nim|ku|Ev tîr ber bi rexê rastê ve ye: →}}
# [[yekser]], [[rasterê]], [[dîrek]], [[dîrekt]]
#: ''Ez '''rast''' ji malê hatim dikanê.''
#: ''Hûn '''rast''' bi 10a êvarê werin gundê me''
# [[destrast]], kesa/ê ji destê [[çep]]ê baştir bi destê rastê dikare [[xebitîn|bixebite]]
#* {{bêmînak|ku}}
# [[rastgir]], [[parêzyar]], [[burjuwa]], [[dijber]]ên [[sosyalîst]]an, [[dijber]]ên [[komunîst]]an
#* {{bêmînak|ku}}
# [[navrast]]
==== Bi alfabeyên din ====
* {{ku-ar|ڕاست}}
* {{ku-kr|рʹаст}}
==== Ji wêjeya klasîk ====
* {{jêder|ku|{{Jêgirtin/Mela Hisênê Bateyî/Mewlûda Kurdî}}|jêgirtin=Jêrî Ednan ta ji 'Ebdullah guhest</br>Bîst û yek bab in, hemî '''rast''' û durust</br>Hin yekî 'Ednan û Me'd û hem Nezar}}
==== Dijmane ====
{{kol3|ku
|çewt
|şaş
|xelet
|derew
|virr
|xwar
|çep
|çepgir
}}
==== Nêzîk ====
* {{g|ku|rest}}
* {{g|ku|restî}}
==== Jê ====
{{kol3|ku|cure=Jê
|rastandin
|rastandî
|rastbêj
|rastbêjî
|rasteqîne
|rastgo
|rastgotî
|rastgoyî
|rastî
|rastîn
|rastînî
|rast bûn<q:lêker>
|rast kirin<q:lêker>
|rast çûn
|rastbûn<q:navdêr>
|rastkirin<q:navdêr>
|rastçûn
|rastbûyî<q:rengdêr>
|rastkirî<q:rengdêr>
}}
==== Bi zaravayên din ====
* {{Z|ckb}}: rast, [[ras]]
* {{Z|sdh}}: rast, [[ras]]
* {{Z|lki}}: rast
* {{Z|hac}}: {{W-|hac|ras}}
* {{Z|zza}}: {{W+|zza|raşt}}, rast
==== Etîmolojî ====
Hevreha soranî {{g|ckb|ڕاست|tr=rast}} û {{g|ckb|ڕاس|tr=ras}}, [[kurdiya başûrî]] ''[[ras]]'', lekî ''ras'', goranî/hewramî ''[[ras]]'', zazakî ''[[raşt]], rast'', belûçî/farisî/gîlekî/mazenderanî {{g|fa|راست|tr=rast}}, tacikî [[рост]] (rost), pehlewî [[𐫡𐫀𐫘𐫤]] (rast) û [[𐫡𐫀𐫘𐫎]] (rasṯ), partî [[𐫡𐫀𐫢𐫤]] (raşt), osetî [[раст]] (rast), sogdî [[𐽀𐽁𐽂]] (ršt) û [[ܪܫܬܝ]] (ršty), peştûyî {{g|ps|رشتيا|tr=rištyā́}}, avestayî [[𐬭𐬀𐬱𐬙𐬀]] (rašta, /reşte/)... {{hv|grc|ὀρεκτός}} (orektós), latînî ''[[rēctus]]'', spanî ''[[recto]]'', îtalî ''[[retto]], [[ritto]]'', portugalî ''[[reto]]''... inglîziya kevn ''[[riht]], [[reht]], [[reoht]]'', inglîziya niha ''[[right]]'' (/rayt/), almanî û holandî ''[[recht]]'', danmarkî ''[[ret]]'', norwecî ''[[rett]]'', swêdî ''[[rätt]]''... hemû ji {{ji|ine-pro|ku|-}} {{recons|ine-pro|h₃reǵtós}}
Peyv ji zimanên îranî ketiye hinek zimanên [[tirkîkî]], bo nimûne: azerî û tirkî ''[[rast#Tirkî|rast]]'', ozbekî ''[[rost]]'', kirgîzî [[ырас]] (ıras). Peyv herwiha ketibû elamî jî wek [[𒊏𒍩𒆪]] (ra-áš-da) û [[𒊏𒆜𒆪]] (ra-iš-da).
;{{biçûk|Çavkanî:
* {{Chyet}}
* {{Horn}}
* {{Ringe}}
* {{Seebold}}
* {{The Tower of Babel}}
* {{Tsabolov}}
* {{Watkins}}
}}
==== Werger ====
{{werger-ser|ne şaş, ne çewt, ne xelet}}
* {{Z|de}}: {{W+|de|korrekt}}, {{W+|de|richtig}}, {{W+|de|einwandfrei}}
* {{Z|as}}: {{W-|as|শুধ|tr=xudho}}, {{W-|as|শুদ্ধ}}
* {{Z|ast}}: {{W-|ast|correutu}}
* {{Z|ain}}: {{W-|ain|ピㇼカ|tr=pirka}}
* {{Z|az}}: {{W+|az|doğru}}
* {{Z|ba}}: {{W-|ba|дөрөҫ}}
* {{Z|be}}: {{W-|be|праві́льны|sc=Cyrl}}
* {{Z|br}}: {{W+|br|reizh}}
* {{Z|bg}}: {{W+|bg|ве́рен|sc=Cyrl}}, {{W+|bg|пра́вилен|sc=Cyrl}}
* {{Z|my}}: {{W+|my|မှန်|sc=Mymr}}
* {{Z|ccc}}: {{W-|ccc|nanatolo}}
* {{Z|cs}}: {{W+|cs|správný|n}}
* {{Z|chr}}: {{W-|chr|ᏚᏳᎪᏛᎢ|tr=duyukdvi}}
* {{Z|zh}}: {{W+|cmn|正確|sc=Hani}}, {{W+|cmn|正确|tr=zhèngquè|sc=Hani}}, {{W+|cmn|對|sc=Hani}}, {{W+|cmn|对|tr=duì|sc=Hani}}, {{W-|cdo|正確|sc=Hani}}, {{W-|cdo|正确|tr=ciáng-káuk|sc=Hani}}
* {{Z|da}}: {{W+|da|korrekt}}, {{W+|da|rigtig}}
* {{Z|id}}: {{W+|id|tepat}}
* {{Z|ar}}: {{W+|ar|صَحِيح|n}}, {{W-|ar|صَوَاب|n}}
* {{Z|hy}}: {{W+|hy|ճիշտ}}
* {{Z|eo}}: {{W-|eo|ĝusta}}
* {{Z|eo}}: {{W+|ro|corect}}
* {{Z|et}}: {{W+|et|õige}}
* {{Z|fa}}: {{W+|fa|درست|tr=dorost|sc=fa-Arab}}
* {{Z|fo}}: {{W+|fo|rættur}}
* {{Z|fi}}: {{W+|fi|oikea}}
* {{Z|fr}}: {{W+|fr|correct}}
* {{Z|gl}}: {{W+|gl|correcto}}
* {{Z|ka}}: {{W-|ka|სწორი}}, {{W-|ka|უშეცდომო}}, {{W-|ka|ზუსტი}}
* {{Z|haw}}: {{W-|haw|pololei}}
* {{Z|hi}}: {{W+|hi|सही|sc=Deva}}, {{W+|hi|ठीक|sc=Deva}}
* {{Z|nl}}: {{W+|nl|correct}}, {{W+|nl|juist}}
* {{Z|he}}: {{W+|he|נָכוֹן|m|tr=nakhon}}, {{W-|he|נְכוֹנָה|f|tr=nekhona}}
* {{Z|ang}}: {{W-|ang|riht}}
* {{Z|en}}: {{W+|en|correct}}, {{W+|en|right}}
* {{Z|it}}: {{W+|it|corretto|n}}, {{W+|it|esatto}}
* {{Z|is}}: {{W-|is|rétt}}
* {{Z|ja}}: {{W+|ja|正しい|tr=ただしい, tadashíi}}, {{W+|ja|正解|tr=せいかい, seikai}}
* {{Z|ca}}: {{W+|ca|correcte}}, {{W+|ca|condret}}
* {{Z|qu}}: {{W-|qu|chanin}}
* {{Z|ky}}: {{W+|ky|туура|sc=Cyrl}}, {{W+|ky|түз|sc=Cyrl}}, {{W+|ky|дурус|sc=Cyrl}}
* {{Z|ko}}: {{W+|ko|옳다}}, {{W+|ko|맞다}}, {{W+|ko|바르다}}, {{W+|ko|정확하다}}
* {{Z|la}}: {{W-|la|correctus}}
* {{Z|lv}}: {{W-|lv|pareizs}}
* {{Z|lo}}: {{W+|lo|ແກ້}}, {{W-|lo|ຖືກ}}
* {{Z|lt}}: {{W-|lt|teisingas}}
* {{Z|mk}}: {{W-|mk|правилен|sc=Cyrl}}, {{W-|mk|верен|sc=Cyrl}}
* {{Z|ms}}: {{W-|ms|benar}}, {{W+|ms|betul}}
* {{Z|mi}}: {{W+|mi|tika}}
* {{Z|hu}}: {{W+|hu|hibátlan}}, {{W+|hu|helyes}}
* {{Z|mvi}}: {{W-|mvi|マツム|tr=matumu}}
* {{Z|no}}: {{W+|no|riktig}}
* {{Z|oc}}: {{W+|oc|corrècte}}, {{W+|oc|condrech}}
* {{Z|uz}}: {{W+|uz|toʻgʻri}}
* {{Z|pl}}: {{W+|pl|prawidłowy|n}}, {{W+|pl|właściwy|n}}, {{W+|pl|poprawny|n}}
* {{Z|pt}}: {{W+|pt|correto}}, {{W+|pt|certo|f}}
* {{Z|kk}}: {{W-|kk|дұрыс|sc=Cyrl}}
* {{Z|rap}}: {{W-|rap|titika}}
* {{Z|ru}}: {{W+|ru|пра́вильный|n}}, {{W+|ru|ве́рный}}, {{W+|ru|корре́ктный}}
* {{Z|sh}}: {{W-|sh|исправан}} / {{W+|sh|ispravan}}
* {{Z|syc}}: {{W-|syc|ܬܪܨ|tr=traṣ|sc=Syrc}}
* {{Z|sk}}: {{W-|sk|správny}}
* {{Z|sl}}: {{W-|sl|pravilen}}
* {{Z|es}}: {{W+|es|correcto}}
* {{Z|su}}: {{W-|su|leres}}
* {{Z|sv}}: {{W+|sv|korrekt}}, {{W+|sv|riktig}}, {{W+|sv|rätt}}, {{W+|sv|felfri}}
* {{Z|tg}}: {{W+|tg|дуруст|sc=Cyrl}}
* {{Z|tl}}: {{W-|tl|tama}}
* {{Z|th}}: {{W+|th|ถูก}}
* {{Z|tr}}: {{W+|tr|doğru}}
* {{Z|tk}}: {{W-|tk|dogry}}, {{W-|tk|dürs}}
* {{Z|ur}}: {{W-|ur|صحیح|tr=sahīh|sc=ur-Arab}}, {{W+|ur|ٹھیک|tr=ṭhīk|sc=ur-Arab}}
* {{Z|uk}}: {{W+|uk|пра́вильний|sc=Cyrl}}
* {{Z|vi}}: {{W+|vi|đúng}}
* {{Z|vo}}: {{W+|vo|verätik}}
* {{Z|cy}}: {{W+|cy|cywir}}
* {{Z|km}}: {{W-|km|ត្រឹមត្រូវ|tr=trəm trəv|sc=Khmr}}
* {{Z|yi}}: {{W-|yi|ריכטיק}}
* {{Z|el}}: {{W+|el|σωστός}}
:* {{Z|grc}}: {{W-|grc|ὀρθός}}
* {{Z|zea}}: {{W-|zea|juust}}, {{W-|zea|sjuust}}, {{W-|zea|goed}}
{{werger-bin}}
{{werger-ser|dijmaneya çepê}}
* {{Z|sq}}: {{W+|sq|djathtë}}
* {{Z|de}}: {{W+|de|direkt}}, {{W+|de|rechts}}
* {{Z|bg}}: {{W+|bg|десен}}, {{W+|bg|дясна}}, [[дясно]] (desen, {{W-|bg|djasna}}, djasno) ''m/f/n''
* {{Z|cs}}: {{W+|cs|pravý}}, {{W-|cs|pravá}}, {{W-|cs|pravé}}
* {{Z|zh}}: {{W+|zh|右|tr=yòu}}
* {{Z|da}}: {{W+|da|højre}}
* {{Z|id}}: {{W+|id|kanan}}
* {{Z|ar}}: {{W-|ar|يَمِين|tr=yemîn}}
* {{Z|eo}}: {{W+|eo|dekstra}}
* {{Z|et}}: {{W-|et|parem}}
* {{Z|fi}}: {{W+|fi|oikea}}, {{W+|fi|oikeanpuoleinen}}
* {{Z|fr}}: {{W+|fr|droit}} {{n}}, {{W+|fr|droite}} {{m}}
* {{Z|gn}}: {{W-|gn|akatúvape}}
* {{Z|nl}}: {{W+|nl|rechts}}, {{W+|nl|rechtse}}
* {{Z|he}}: {{W+|he|ימין|tr=yemîn}}
* {{Z|io}}: {{W+|io|dextra}}
* {{Z|en}}: {{W+|en|right}} (not [[left]])
* {{Z|ga}}: {{W-|ga|deas}}
* {{Z|it}}: {{W+|it|destro}} {{n}}, {{W+|it|destra}} {{m}}
* {{Z|is}}: {{W+|is|hægri}}
* {{Z|ja}}: {{W+|ja|右|tr=[[みぎ]], migí}}
* {{Z|ca}}: {{W+|ca|dret}}
* {{Z|ko}}: {{W+|ko|오른|tr=oreun}}, [[바른]] (bareun)
* {{Z|la}}: {{W-|la|dexter}} {{n}}, {{W-|la|dextra}} {{m}}, {{W-|la|dextrum}} {{nt}}
* {{Z|hu}}: {{W+|hu|jobb}}
* {{Z|mic}}: {{W-|mic|badadujk}}
* [[ojibweyî]]: [[gichinik]]
* [[pitjantjatjarayî]]: [[waku]]
* {{Z|pl}}: {{W+|pl|prawy}} {{n}}, {{W-|pl|prawa}} {{m}}, {{W-|pl|prawe}} {{nt}}
* {{Z|pt}}: {{W+|pt|direito}} {{n}}, {{W+|pt|direita}} {{m}}
* {{Z|ro}}: {{W+|ro|drept}}, {{W+|ro|dreapta}}
* {{Z|ru}}: {{W+|ru|правый}}, {{W+|ru|правая}}, [[правое]] (právyj, {{W-|ru|právaja}}, právoje) ''m/f/n''
* {{Z|sh}}: {{W+|sh|desni}}
* [[lakotayî]]: [[isloyatan]]
* {{Z|sl}}: {{W-|sl|desni}} {{n}}, {{W-|sl|desna}} {{m}}, {{W-|sl|desno}} {{nt}}
* {{Z|es}}: {{W+|es|derecho}} {{n}}, {{W+|es|derecha}} {{m}}
* {{Z|sv}}: {{W+|sv|höger}}
* {{Z|th}}: {{W+|th|ขวา|tr=khwáá}}
* {{Z|te}}: {{W+|te|కుడి|tr=kuDi}}
* {{Z|tr}}: {{W+|tr|sağ}}
* {{Z|vi}}: {{W+|vi|thẳng|tr=straight}}
* {{Z|el}}: {{W+|el|δεξιός|tr=deksiós}}
{{werger-bin}}
{{werger-ser|ne xwehr, ne çemandî}}
* {{Z|de}}: {{W+|de|direkt}}, {{W+|de|gerade}}
* {{Z|bg}}: {{W+|bg|прав|tr=prav}}
* {{Z|da}}: {{W+|da|ret}}, {{W+|da|lige}}
* {{Z|id}}: {{W+|id|lurus}}
* {{Z|ar}}: {{W-|ar|مباشرة}}, {{W-|ar|مستقيم}}
* {{Z|eo}}: {{W+|eo|rekta}}
* {{Z|et}}: {{W-|et|otse}}
* {{Z|fa}}: {{W-|fa|بی اشتباه}}, {{W-|fa|بی خطا}}, {{W+|fa|درست}}, {{W+|fa|راست}}, {{W+|fa|صحیح}}, {{W+|fa|حقیقت}}, {{W+|fa|میدان}}, {{W+|fa|صحیح|guman=erê}}
* {{Z|fi}}: {{W+|fi|suora}}
* {{Z|fr}}: {{W+|fr|droit}}
* {{Z|nl}}: {{W+|nl|recht}}
* {{Z|en}}: {{W+|en|straight}}, {{W+|en|right}}
* {{Z|it}}: {{W+|it|diritto}}
* {{Z|is}}: {{W+|is|beint}} {{nt}}, {{W+|is|beinn}} {{n}}, {{W+|is|bein}} {{m}}
* {{Z|ja}}: {{W+|ja|まっすぐ|tr=massúgu}}
* {{ko}} : [[곧다]] (godda, {{W-|ko|got-)}}, [[바르다]] (bareuda)
* {{g|ku|ojibweyî]]: [[gwayak}}
* {{Z|hu}}: {{W+|hu|egyenes}}
* {{Z|pt}}: {{W+|pt|direito}}, {{W+|pt|reto}}
* {{Z|ru}}: {{W+|ru|прямой|tr=prjamój}}
* {{Z|es}}: {{W+|es|derecho}}, {{W+|es|recto}}, {{W+|es|justo}}
* {{Z|sv}}: {{W+|sv|rak}}
* {{Z|tly}}: {{W-|tly|rost}}
* {{Z|th}}: {{W-|th|ดิ่ว|tr=diù}}, [[ตรง]] (dtrohng)
* {{Z|tr}}: {{W+|tr|düz}}
{{werger-bin}}
== {{ziman|zza}} ==
=== Rengdêr ===
{{rengdêr|zza}}
# {{g|ku|rast|tr=-}}
#* {{bêmînak|zza}}
==== Herwiha ====
* {{g|zza|raşt}}
== {{ziman|sv}} ==
=== Navdêr ===
{{navdêr|sv}}
# [[bênvedan]], [[vehesîn]], [[istirehet]], [[pişû]]
#* {{bêmînak|sv}}
== {{ziman|tr}} ==
=== Rengdêr ===
{{rengdêr|tr}}
# {{g|ku|rast}}
#* {{bêmînak|tr}}
# [[tûş]], [[leqayî]], [[liqa]], [[tesadûf]]
#* {{bêmînak|tr}}
# {{g|ku|rast}}
#* {{bêmînak|tr}}
enmod6h6tbg3ttndae3mwicyughbu95
e-kitêb
0
4501
6241886
6129489
2026-07-12T21:33:08Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241886
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|e-kitêb|mê}}
{{navdêr|ku|z=m}}
# {{K|ku|kitêb}} '''[[kitêb]]ên [[elektronîkî]]''': [[pirtûk]]ên ne li ser [[kaxez]]ê lê bi [[form]]ek [[elektronîkî]] ango [[karebayî]] hatine [[weşandin]] (bi taybetî li ser [[Internet]]ê)
#* {{bêmînak|ku}}
==== Herwiha ====
* [[e-kîtab]]
==== Hevmane ====
* [[e-pirtûk]]
==== Bide ber ====
* [[e-name]]
* [[e-poste]]
==== Etîmolojî ====
Ji {{qertaf|ku|e|pirtûk}}.
==== Werger ====
{{werger-ser}}
* {{Z|fi}}: {{W|fi|e-kirja}}
* {{Z|en}}: {{W|en|e-book}}
* {{Z|sv}}: {{W|sv|e-bok}}
* {{Z|tr}}: {{W|tr|e-kitap}}
{{werger-bin}}
e2tzlz5bratnwcaz8r6zo05uc6k1vn5
6241890
6241886
2026-07-12T21:35:29Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241890
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|e-kitêb|mê}}
{{navdêr|ku|z=m}}
# {{K|ku|kitêb}} '''[[kitêb]]ên [[elektronîkî]]''': [[pirtûk]]ên ne li ser [[kaxez]]ê lê bi [[form]]ek [[elektronîkî]] ango [[karebayî]] hatine [[weşandin]] (bi taybetî li ser [[Internet]]ê)
#* {{bêmînak|ku}}
==== Herwiha ====
* [[e-kîtab]]
==== Hevmane ====
* [[e-pirtûk]]
==== Bide ber ====
* [[e-name]]
* [[e-poste]]
==== Etîmolojî ====
Ji {{qertaf|ku|e-<id:dijîtal>|kitêb}}.
==== Werger ====
{{werger-ser}}
* {{Z|fi}}: {{W|fi|e-kirja}}
* {{Z|en}}: {{W|en|e-book}}
* {{Z|sv}}: {{W|sv|e-bok}}
* {{Z|tr}}: {{W|tr|e-kitap}}
{{werger-bin}}
daw0ssglckijapmvmznas6yladmj7xe
evîn
0
5311
6241894
6234883
2026-07-12T21:39:14Z
Wikihez
7344
/* Jê */
6241894
wikitext
text/x-wiki
{{bnr-h|evin|êvîn|Evîn|Evin}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-evîn.wav|Deng|Bidlîs}}
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|evîn|mê}}
[[Wêne:Zoom AntonioCanova PsycheRevivedByCupidsKiss.JPG|thumb|Kupîd, xudayê [[yûnanî]]-[[romanî]] yê '''evînê''', bi [[maç]]ekê Psîşêyê ji nû ve [[vejandin|vedijîne]]. Heykelê 1787-1793 yê Canova (Kanova).]]
{{navdêr|ku|z=m}}
# [[hezkirin|hezkirin]]a [[kûr]] (bi taybetî ji bo mirovan: [[zelam]] ji [[jin|jinê]], jin ji zelamî, zelam ji zelamî, jin ji jinê û [[hwd.]])
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Şubhê Ferhad û Şirînê</br>Wer ji ber 'işq û '''evînê'''</br>Min di rê çit ev kilox}}
==== Bi alfabeyên din ====
* {{ku-ar|ئهڤین}}
==== Herwiha ====
* {{g|ku|vîn}} (2)
* {{g|ku|êvîn}}
* {{g|ku|hêvîn}}
==== Hevmane ====
{{kol2|ku|
|dildarî
|eşq
|mihbet
|yaratî
}}
==== Jê ====
{{kol3|ku|cure=Jê
|bievîn
|bievînî
|evîndar
|evîndarî
|evînî
|evînname
|evînnameyî
|evînbaz
|barê evînê
[[bersiv]]a evîna (kesekê/î) (ne)dan
|derdê evînê
| evîna bi [[dîtin]]a [[pêşîn]]
| evîna [[canî]]
| evîna [[giyanî]]
| evîna [[hevber]]î filankesê/î
| evîna [[jidil]]
| evîna [[jin û mêr]]an
| evîna [[ji qesta]]
| evîna keç û kurran
|evîn kirin
|evîna platonî
| ketin evînê
}}
==== Etîmolojî ====
Herwiha {{q|ku|hevîn}}, forma "[[kurdî]]kirî" ji peyva "{{q|ku|hebîn}}", belkî bi têkilkirina li gel peyva "{{q|ku|vîn}}, {{q|ku|viyan}}" ya esil-kurdî, ji {{qertaf|ziman1=ar|ku|حب|tr1=ḥebbe|w1=[[hez]] kirin, [[vîn]], [[viyan]]|-în}} ya kurdî, têkilî {{g|ar|حب|tr=ḥubb|w=evîn, [[eşq]], [[viyan]], [[işq]]}}, [[hevreh]]a {{hv|arc|ܚܘܒܐ|tr=ḥubba|w=evîn, [[hez]]kirin, [[viyan]], [[vîn]]}}, {{hv|he|אהב|tr=ahava}}, ugarîtî {{g|uga|𐎀𐎅𐎁𐎚|tr=ảhbt/ʾahabtu}}. Bo guherîna b/v bide ber "bab/bav, xirab/xirav, vapor/bapor..." Herwiha bo ketina "h" bide ber van peyvan: hesp/esp, erzan/herzan, ewr/hewr, asin/hesin..." Ne ji "e+vîn" hatiye çêkirin ji ber ku di kurdî pêşpirtikek wisa ya [[peyvsaz]] nîne.
{{g|ckb|ئهوین|tr=[[ewîn]]}} ya soranî vê dawiyê ji kurmancî ([[behdînî]]) hatiye wergirtin û hê jî baş di soranî de belav nebûye. Ji eynî rehê erebî: [[hebandin]], [[hebîb]], [[mehbûb]], [[mihbet]]...
Lê wekî din, dibe ku ew kanibe ji evistin be (forma niha -ev- , jê hez kirin) peyvê ku ji rehek îranî ye.
;{{biçûk|Çavkanî:
* {{Çabolov|r=36-37}}
* Husein Muhammed: Rehnas, Ferhenga etîmolojiya kurdî, 2016
* {{Hasanpoor|r=107}}
}}
==== Dûnde ====
* {{dû|ckb|ئهوین|deyn=1}}
==== Werger ====
{{werger-ser}}
* {{Z|ady}}: {{W-|ady|шӏулъэгъуныгъ}}
* {{Z|af}}: {{W+|af|liefde}}
* {{Z|sq}}: {{W+|sq|dashuri|m}}
* {{Z|de}}: {{W+|de|Liebe|m}}, {{W+|de|Zuneigung|m}}, {{W+|de|Minne|m}}
*: {{Z|gsw}}: {{W-|gsw|Liäbi}}, {{W-|gsw|Liebi}}
*: {{Z|gmw-ecg}}: {{W-|gmw-ecg|Liebe|m}}
* {{Z|alt}}: {{W-|alt|сӱӱ-}}, {{W-|alt|сӱӱш}}, {{W-|alt|сӱӱм}}
* {{Z|zgh}}: {{W-|zgh|ⵜⴰⵢⵔⵉ|m}}
* {{Z|am}}: {{W-|am|ፍቅር}}, {{W-|am|መውደድ}}
* {{Z|an}}: {{W-|an|aimor}}
* {{Z|arc}}:
*: {{Z|syc}}: {{W-|syc|ܚܘܒܐ|n|tr=ḥūbbā}}
* {{Z|rup}}: {{W-|rup|vreari|m}}, {{W-|rup|vreare|m}}, {{W-|rup|agapi|m}}, {{W-|rup|sivdã|m}}
* {{Z|as}}: {{W-|as|মৰম}}, {{W-|as|চেনেহ}}
* {{Z|ast}}: {{W-|ast|amor|n}}
* {{Z|ay}}: {{W-|ay|amawaña}}
* {{Z|az}}: {{W+|az|sevgi}}, {{W+|az|eşq}}, {{W+|az|məhəbbət}}
* {{Z|ban}}: {{W-|ban|tresna}}
* {{Z|eu}}: {{W+|eu|amodio}}, {{W+|eu|maitasun}}
* {{Z|ba}}: {{W-|ba|мөхәббәт}}, {{W-|ba|һөйөү}}
* {{Z|bar}}: {{W-|bar|Liab}}
* {{Z|be}}: {{W-|be|любо́ў|m}}, {{W-|be|каха́нне|nt}}
* {{Z|bn}}: {{W+|bn|মহব্বত}}, {{W+|bn|ভালোবাসা}}
* {{Z|bcl}}: {{W-|bcl|pagkamoot}}
* {{Z|br}}: {{W+|br|karantez|m}}
* {{Z|bg}}: {{W-|bg|любо́в|m}}, {{W-|bg|о́бич|m}}
* {{Z|my}}: {{W+|my|အချစ်}}, {{W+|my|မေတ္တာ}}
* {{Z|bua}}: {{W-|bua|дуран}}
* {{Z|cs}}: {{W+|cs|láska|m}}
* {{Z|chr}}: {{W-|chr|ᏥᎨᏳᎢ}}
* {{Z|zh}}:
*: {{Z|yue}}: {{W-|yue|愛|tr=oi3}}, {{W-|yue|愛情|tr=oi3 cing4}}
*: {{Z|dng}}: {{W-|dng|нэ}}
*: {{Z|gan}}: {{W-|gan|愛|tr=ngai4}}
*: {{Z|hak}}: {{W-|hak|愛}}, {{W-|hak|愛|tr=oi}}
*: {{Z|cjy}}: {{W-|cjy|愛|tr=ghai3}}
*: {{Z|cmn}}: {{W+|cmn|愛|tr=ài}}, {{W+|cmn|愛情|tr=àiqíng}}
*: {{Z|mnp}}: {{W-|mnp|愛|tr=o̿}}
*: {{Z|cdo}}: {{W-|cdo|愛}}, {{W-|cdo|愛|tr=ái}}
*: {{Z|nan}}: {{W+|nan|愛情|tr=ài-chîng}}, {{W+|nan|情愛|tr=chêng-ài}}, {{W+|nan|愛|tr=ài}}
*: {{Z|wuu}}: {{W-|wuu|愛}}
*: {{Z|hsn}}: {{W-|hsn|愛|tr=ngai4}}
* {{Z|cv}}: {{W-|cv|юрату}}
* {{Z|dlm}}: {{W-|dlm|amaur}}
* {{Z|da}}: {{W+|da|kærlighed|g}}
* {{Z|dar}}: {{W-|dar|дигай}}
* {{Z|dv}}: {{W-|dv|ލޯބި}}
* {{Z|dlg}}: {{W-|dlg|бага|tr=baga}}
* {{Z|ovd}}: {{W-|ovd|tjärliek|n}}
* {{Z|id}}: {{W+|id|cinta}}, {{W+|id|suka}}
* {{Z|arz}}: {{W-|arz|حب|n|tr=ḥob}}
* {{Z|ar}}: {{W+|ar|حُبّ|n}}, {{W-|ar|مَحَبَّة|m}}, {{W+|ar|عِشْق|m}}
*: {{Z|ajp}}: {{W-|ajp|حب|n|tr=ḥubb}}, {{W-|ajp|محبة|n|tr=maḥabba}}, {{W-|ajp|غرام|n|tr=ḡarām}}
*: {{Z|acw}}: {{W-|acw|حب|n|tr=ḥubb}}
*: {{Z|ajp}}: {{W-|ajp|حب|n|tr=ḥubb}}, {{W-|ajp|محبة|n|tr=maḥabba}}, {{W-|ajp|غرام|n|tr=ḡarām}}
*: {{Z|apd}}: {{W-|apd|ريدة|tr=rĩda}}, {{W-|apd|حب|tr=ḥubb}}
* {{Z|hy}}: {{W+|hy|սեր}}
* {{Z|myv}}: {{W-|myv|вечкема}}
* {{Z|eo}}: {{W+|eo|amo}}, {{W-|eo|korinklino}}, {{W-|eo|kareco}}, {{W-|eo|amsento}}
* {{Z|et}}: {{W+|et|armastus}}
* {{Z|ee}}: {{W-|ee|lɔlɔ̃}}
* {{Z|gur}}: {{W-|gur|nõŋlʋm|c14}}
* {{Z|fa}}: {{W+|fa|عشق|tr='ešq}}, {{W+|fa|محبت|tr=mohabbat, mahabbat}}, {{W+|fa|مهر|tr=mehr}}
* {{Z|phn}}: {{W-|phn|𐤇𐤌𐤃𐤕|m}}
* {{Z|fo}}: {{W-|fo|kærleiki|n}}, {{W+|fo|ást|m}}
* {{Z|fi}}: {{W+|fi|rakkaus}}
* {{Z|fr}}: {{W+|fr|amour|n}}
* {{Z|fur}}: {{W-|fur|amôr|n}}
* {{Z|fy}}: {{W-|fy|leafde}}
* {{Z|gd}}: {{W+|gd|gaol|n}}, {{W+|gd|gràdh|n}}, {{W-|gd|spèis|m}}, {{W-|gd|rùn|n}}
* {{Z|gag}}: {{W-|gag|sevgi}}
* {{Z|gl}}: {{W+|gl|amor|n}}
* {{Z|sdn}}: {{W-|sdn|amóri}}
* {{Z|got}}: {{W-|got|𐍆𐍂𐌹𐌾𐌰𐌸𐍅𐌰|m}}
* {{Z|gu}}: {{W+|gu|પ્રેમ}}
* {{Z|ka}}: {{W-|ka|სიყვარული}}
* {{Z|gn}}: {{W-|gn|mborayhu}}
* {{Z|ht}}: {{W-|ht|renmen|m}}
* {{Z|haw}}: {{W-|haw|aloha}}
* {{Z|ha}}: {{W-|ha|ƙauna}}
* {{Z|hi}}: {{W+|hi|प्यार|n}}, {{W+|hi|प्रेम|n}}, {{W-|hi|इश्क़|n}}, {{W+|hi|मुहब्बत|m}}, {{W+|hi|सम्मोह|n}}, {{W+|hi|स्नेह|n}}, {{W+|hi|अनुराग|n}}, {{W+|hi|प्रीति|m}}, {{W+|hi|इष्ट}}
* {{Z|ho}}: {{W-|ho|lalokau}}
* {{Z|hil}}: {{W-|hil|higugma}}
* {{Z|meu}}: {{W-|meu|lalokau}}
* {{Z|mww}}: {{W-|mww|txoj kev hlub}}
* {{Z|dum}}: {{W-|dum|minne|m}}
* {{Z|nl}}: {{W+|nl|liefde|m}}
* {{Z|hrx}}: {{W-|hrx|Lieb|m}}
* {{Z|he}}: {{W-|he|אַהֲבָה|m|tr=ahavá}}
* {{Z|io}}: {{W+|io|amo}}
* {{Z|ilo}}: {{W-|ilo|ayat}}
* {{Z|ang}}: {{W-|ang|lufu|m}}
* {{Z|enm}}: {{W-|enm|love}}
* {{Z|en}}: {{W+|en|love}}
* {{Z|izh}}: {{W-|izh|suvvaahusse}}
* {{Z|ia}}: {{W+|ia|amor}}
* {{Z|ga}}: {{W+|ga|grá|n}}, {{W-|ga|armacas|n}}
* {{Z|it}}: {{W+|it|amore|n}}
* {{Z|is}}: {{W+|is|ást}}, {{W+|is|kærleikur|n}}, {{W+|is|elska}}
* {{Z|ja}}: {{W+|ja|愛|tr=あい, ai}}, {{W+|ja|愛情|tr=あいじょう, aijō}}, {{W+|ja|愛好|tr=あいこう, aikō}}
* {{Z|kaw}}: {{W-|kaw|tṛṣṇa}}
* {{Z|jv}}: {{W+|jv|tresna}}, {{W+|jv|katresnan|tr=katresnan}}, {{W-|jv|cinta|tr=cinta}}
* {{Z|jje}}: {{W-|jje|ᄉᆞ랑}}
* {{Z|kl}}: {{W-|kl|asanninneq}}
* {{Z|kam}}: {{W-|kam|wendo}}
* {{Z|kn}}: {{W+|kn|ಪ್ರೀತಿ}}
* {{Z|pam}}: {{W-|pam|lugud}}, {{W-|pam|irug}}, {{W-|pam|sinta}}, {{W-|pam|mal}}, {{W-|pam|buri}}, {{W-|pam|ibug}}
* {{Z|krc}}: {{W-|krc|сюймеклик}}
* {{Z|ca}}: {{W+|ca|amor|n}}
* {{Z|qu}}: {{W-|qu|khuya}}
* {{Z|ky}}: {{W+|ky|сүйүү}}, {{W+|ky|махабат}}, {{W+|ky|сүйүш}}
* {{Z|ki}}: {{W-|ki|wendo}}
* {{Z|si}}: {{W-|si|ආදරය}}
* {{Z|rw}}: {{W-|rw|urukundo|c11}}
* {{Z|ko}}: {{W+|ko|사랑}}, {{W+|ko|애정}}
* {{Z|kw}}: {{W-|kw|kerensa|m}}
* {{Z|co}}: {{W+|co|amore|n}}, {{W+|co|amori|n}}
* {{Z|ltg}}: {{W-|ltg|mīleiba}}, {{W-|ltg|mīla}}
* {{Z|la}}: {{W+|la|amor|n}}, {{W-|la|caritas|m}}
* {{Z|lv}}: {{W+|lv|mīlestība|m}}, {{W-|lv|mīla|m}}
* {{Z|lo}}: {{W-|lo|ຄວາມຮັກ}}
* {{Z|lzz}}: {{W-|lzz|ოროფა}}
* {{Z|ln}}: {{W-|ln|bolingo|14}}
* {{Z|lij}}: {{W-|lij|amù|n}}
* {{Z|li}}: {{W-|li|leefde|m}}
* {{Z|lt}}: {{W+|lt|meilė|m}}
* {{Z|liv}}: {{W-|liv|ārmastõz}}
* {{Z|lmo}}: {{W-|lmo|amór}}
* {{Z|lg}}: {{W-|lg|omukwaano}}
* {{Z|luy}}: {{W-|luy|vuyanzi}}
* {{Z|lb}}: {{W+|lb|Léift|m}}
* {{Z|mdh}}: {{W-|mdh|kasih}}
* {{Z|mk}}: {{W-|mk|љубов|m}}
* {{Z|ml}}: {{W+|ml|സ്നേഹം}}, {{W+|ml|ഇഷ്ടം}}
* {{Z|ms}}: {{W+|ms|cinta}}, {{W+|ms|sayang}}
* {{Z|mt}}: {{W-|mt|imħabba|m}}
* {{Z|gv}}: {{W-|gv|graih|n}}
* {{Z|mi}}: {{W+|mi|aroha}}
* {{Z|mrw}}: {{W-|mrw|kasi}}
* {{Z|mr}}: {{W-|mr|प्रेम}}, {{W-|mr|प्रीति}}
* {{Z|gun}}: {{W-|gun|mborayvu}}
* {{Z|fit}}: {{W-|fit|rakhaus}}
* {{Z|hu}}: {{W+|hu|szeretet}}, {{W+|hu|szerelem}}
* {{Z|xmf}}: {{W-|xmf|ჸოროფა}}
* {{Z|mer}}: {{W-|mer|wendo}}
* {{Z|egy}}: {{W-egy|mrwt|m|h=U7:r-w&t-A2}}
* {{Z|lus}}: {{W-|lus|hmangaihna}}
* {{Z|mwl}}: {{W-|mwl|amor}}
* {{Z|mn}}:
*: Kirîlî: {{W+|mn|хайр}}, {{W-|mn|дур хүсэл}}
* {{Z|mxi}}: {{W-|mxi|אמורי|n|tr=amore}}
* {{Z|nag}}: {{W-|nag|morom}}
* {{Z|nah}}: {{W-|nah|tlazohtlaliztli}}, {{W-|nah|tlasojtlalistli}}
* {{Z|nnt}}: {{W-|nnt|quámmősch}}
* {{Z|nv}}: {{W-|nv|ayóóʼóʼóʼní}}
* {{Z|ne}}: {{W+|ne|माया}}
* {{Z|nrf}}: {{W-|nrf|amour|n}}
* {{Z|no}}:
*: {{Z|nb}}: {{W+|nb|kjærlighet|n}}, {{W-|nb|elsk|n}}, {{W+|nb|kjærleik|n}}
*: {{Z|nn}}: {{W+|nn|kjærleik|n}}, {{W-|nn|elsk|n}}, {{W-|nn|åst|m}}
* {{Z|oj}}: {{W-|oj|zaagi'idiwin|in}}
* {{Z|ryu}}: {{W-|ryu|なさき|tr=nasaki}}
* {{Z|pro}}: {{W-|pro|amor}}
* {{Z|oc}}: {{W+|oc|amor}}
* {{Z|or}}: {{W+|or|ପ୍ରେମ}}
* {{Z|os}}: {{W-|os|уарзондзинад}}
* {{Z|ug}}: {{W-|ug|مۇھەببەت}}, {{W-|ug|ئاشىق}}, {{W-|ug|ئاشىقلىق}}
* {{Z|uz}}: {{W+|uz|sevgi}}, {{W+|uz|muhabbat}}
* {{Z|ps}}: {{W+|ps|مينه|m|tr=mína}}
* {{Z|pms}}: {{W-|pms|amor|n}}
* {{Z|pdt}}: {{W-|pdt|Leew|m}}
* {{Z|pl}}: {{W+|pl|miłość|m}}
* {{Z|pt}}: {{W+|pt|amor|n}}
* {{Z|prg}}: {{W-|prg|mīli}}
* {{Z|pa}}: {{W-|pa|ਪਿਆਰ|n}}
* {{Z|kk}}: {{W-|kk|ғашықтық}}, {{W-|kk|махаббат}}, {{W-|kk|сүйіс}}
* {{Z|rhg}}: {{W-|rhg|ador}}, {{W-|rhg|mohábboth}}
* {{Z|rgn}}: {{W-|rgn|amôr|n}}
* {{Z|rm}}: {{W-|rm|charezza|m}}
* {{Z|ro}}: {{W+|ro|iubire|m}}, {{W+|ro|dragoste|m}}, {{W+|ro|amor|nt}}
* {{Z|ru}}: {{W-|ru|любо́вь|m}}
* {{Z|se}}: {{W-|se|ráhkisvuohta}}
* {{Z|sm}}: {{W-|sm|alofa}}
* {{Z|sa}}: {{W+|sa|अनुराग|n}}, {{W+|sa|प्रेमन्|n|nt}}
* Sardinian:
*: {{Z|sc}}: {{W-|sc|amóri}}
*: {{Z|sc}}: {{W-|sc|ameddu}}
* {{Z|sdc}}: {{W-|sdc|amóri}}
* {{Z|ceb}}: {{W-|ceb|gugma}}
* {{Z|scn}}: {{W+|scn|amuri|n}}
* {{Z|sd}}: {{W+|sd|محبت|m|tr=mahbbàtà}}, {{W+|sd|عشق|n|tr='išqù}}, {{W-|sd|پیار|n|tr=pyārù}}, {{W-|sd|لَنو|n|tr=lôve}}
* {{Z|sh}}:
*: Kirîlî: {{W-|sh|љу́бав|m}}
*: Latînî: {{W+|sh|ljúbav|m}}
* {{Z|syl}}: {{W-|syl|ꠝꠣꠄꠣ}}
* {{Z|cu}}:
*: Kirîlî: {{W-|cu|любꙑ|m}}
* {{Z|sk}}: {{W+|sk|láska|m}}
* {{Z|sl}}: {{W+|sl|ljubezen|m}}
* {{Z|so}}: {{W+|so|jacayl}}
* Sorbî:
*: {{Z|dsb}}: {{W-|dsb|lubosć|m}}
* {{Z|es}}: {{W+|es|amor|n}}
* {{Z|su}}: {{W-|su|asih}}, {{W+|su|deudeuh}}, {{W-|su|nya'ah}}
* {{Z|sux}}: {{W-|sux|𒀀𒊏𒄠𒈬|tr=arammu}}
* {{Z|sw}}: {{W+|sw|upendo}}
* {{Z|sv}}: {{W+|sv|kärlek|g}}
* {{Z|cjs}}: {{W-|cjs|кӧлениш|tr=köleniş}}
* {{Z|tg}}: {{W+|tg|муҳаббат}}, {{W+|tg|ишқ}}
* {{Z|tl}}: {{W+|tl|pag-ibig}}, {{W-|tl|pagmamahal}}
* {{Z|ta}}: {{W+|ta|அன்பு}}, {{W+|ta|பாசம்}}
* {{Z|th}}: {{W+|th|ความรัก}}
* {{Z|te}}: {{W+|te|ప్రేమ}}
* {{Z|tzm}}: {{W-|tzm|ⵜⴰⵢⵔⵉ}}
* {{Z|crh}}: {{W-|crh|süygü}}
* {{Z|tt}}: {{W-|tt|ярату}}
* {{Z|tet}}: {{W-|tet|domin}}
* {{Z|ti}}: {{W-|ti|ፍቕሪ}}
* {{Z|tr}}: {{W+|tr|sevgi}}, {{W+|tr|sevi}}, {{W+|tr|aşk}}, {{W+|tr|emre}}
* {{Z|tk}}: {{W-|tk|yşk}}, {{W-|tk|söýgi}}
* {{Z|bo}}: {{W-|bo|བརྩེ་དུང}}
* {{Z|tpi}}: {{W-|tpi|lav}}
* {{Z|xto}}: {{W-|xto|tunk}}
* {{Z|txb}}: {{W-|txb|tankw}}, {{W-|txb|larauñe}}
* {{Z|tyv}}: {{W-|tyv|ынакшыл}}
* {{Z|ur}}: {{W+|ur|محبت|m|tr=muhabbat}}, {{W+|ur|عشق|n|tr='iśq}}, {{W+|ur|پیار|n|tr=pyār}}
* {{Z|uk}}: {{W-|uk|любо́в|m}}, {{W-|uk|коха́ння|nt}}
* {{Z|vi}}: {{W+|vi|tình yêu}}, {{W+|vi|ái tình}}
* {{Z|vo}}: {{W+|vo|löf}}, {{W+|vo|lelöf}}
* {{Z|wa}}: {{W+|wa|amour|n}}, {{W-|wa|amor|n}}
* {{Z|cy}}: {{W+|cy|cariad|n}}
* {{Z|wo}}: {{W+|wo|mbëggeel}}
* {{Z|km}}: {{W-|km|សេចក្ដីស្រឡាញ់|tr=sackdəy srɑlañ}}
* {{Z|xh}}: {{W-|xh|uthando}}
* {{Z|sah}}: {{W-|sah|таптал}}
* {{Z|yi}}: {{W-|yi|אַהבֿה|m|tr=aave}}, {{W-|yi|ליבע|m}}, {{W-|yi|ליבשאַפֿט|m}}
* {{Z|yol}}: {{W-|yol|loove}}
* {{Z|yo}}: {{W-|yo|ìfẹ́}}
* {{Z|el}}: {{W+|el|αγάπη|m}}, {{W+|el|έρωτας|n}},
*: Kevn: {{W-|grc|ἀγάπη|m}}, {{W-|grc|φιλία|m}}, {{W-|grc|ἔρως|n}}, {{W-|grc|στοργή|m}}
* {{Z|za}}: {{W-|za|aiqcingz}}, {{W-|za|aiq}}
* {{Z|zu}}: {{W+|zu|uthando|c11}}
{{werger-bin}}
: {{werger çavkanî|en|beş=Ev qismê Wergerê|love|oldid=75615682}}
cxjwmomi68uhxlkordka0x46ebras3m
-e
0
25432
6241840
6240296
2026-07-12T17:19:08Z
Kurdanparez
14556
/* Paşgir 1 */
6241840
wikitext
text/x-wiki
{{binêre herwiha/e}}
== {{ziman|ku}} ==
=== Paşgir ===
{{paşgir|ku}}
# [[paşbendik|Paşbendika]] [[kesîn]] ya kesê sêyem yê [[yekjimar]] li [[dema niha]].
#: {{hevmane|ku|-it}}
#: ''Ew dik'''e''', ew dixw'''e''', ew dibêj'''e'''.
# [[paşbendik|Paşbendikek]] e ku peyvên [[zayendmê]] yên [[yekjimar]] û [[nediyar]] bi [[diyarker]]ên wan ve [[girê|girê dide]].
#: {{mk|ku|pirtûkek'''e''' kevn, jinek'''e''' spehî}}
# [[paşbendik|Paşbendikek]] e hin peyvên nû ji yên heyî pê tên çêkirin.
#: {{sufex|ku|heft|hefte}}
#: {{sufex|ku|çandin|çande}}
#: {{sufex|ku|şil|şile}}
#: {{sufex|ku|nexş|nexşe}}
# [[paşbendik|Paşbendikek]] e wateya "ya / yê ku gelek dike yan dikare" dide peyvê.
#: {{sufex|ku|zan|zane<t:kesê gelek dizane>}}
#: {{sufex|ku|xwarin<cuda:xwer>|xwere<t:kesê ku pirr dixwe>}}
==== Bide ber ====
* {{g|ku|e}}, {{g|ku|e-}}, {{g|ku|-e-}}
==== Binere herwiha ====
* {{g|ku|-a}}, {{g|ku|-ê}}, {{g|ku|-i}}, {{g|ku|-î}}, {{g|ku|-o}}
==== Jê ====
{{paşgirbibîne|ku}}
==== Etîmolojî ====
'''Raman 1:''' Ji {{jinûvesazî|-ed}}, herwiha {{q|ku|-it}}, hevreha {{hv|fa|ـﺪ|tr=-ed}}, ji {{mîr|ine-pro|ku|*-iteh₂}}.
'''Raman 2:''' Guhertoyeke {{q|ku|-eka}}.
'''Raman 3:''' Ji {{jinûvesazî|-ek}} / {{jinûvesazî|-eg}}, hevreha {{q|ku|-ik}}.
'''Raman 4:''' Guhertoyeke {{q|ku|-a}}.
== {{ziman|zza}} ==
===Bilêvkirin===
* {{zza-IPA|"e}}
=== Paşgir 1 ===
{{paşgir|zza}}
# {{maneid|zza|mêker}} [[paşbendik|Paşbendikekê]] mêker, yê navdêr mê dike.
#: {{sufex|zza|her<z:n>|here<z:m>}}
==== Jê ====
{{paşgirbibîne|zza|id=mêker}}
====Etîmolojî====
Hevreha {{hv|hac|ـە}}.
=== Paşgir 2 ===
{{paşgir|zza}}
# [[paşbendik|Paşbendikekê]] li {{g|ku|lêker|lêkerên}} gerguhêz yê dema borî, wextê ku bireserê lêker yekjimar û ''mê'' ye.
#: ''Layikî çeneke paçî kerd'''e'''.'' Lawikî keçik {{g|ku|paç}} kir.
====Bide ber====
* {{g|zza|-î}}, ji bo bireserê lêker yê pirjimar.
== {{ziman|eo}} ==
=== Bilêvkirin ===
{{eo-IPA|e}}
* {{deng|eo|LL-Q143 (epo)-Lepticed7--e.wav|Deng|dever=Toulouse, Fransa}}
=== Paşgir ===
{{paşgir|eo}}
# Paşgira ku [[hoker]]an çêdike.
#: {{sufex|eo|bona<t:baş><pos:rengdêr>|bone<t:baş><pos:hoker>}}
# Tê paş peyvên ku cih nîşan dikin.
==== Binêre herwiha ====
{{kol3|eo|sernav=Peyvên cih nîşan dikin
| {{g|eo|ĉie|t=her der}}
| {{g|eo|ie|t=dereke}}
| {{g|eo|kie|t=li kû derê}}
| {{g|eo|nenie|t=ne dereke}}
| {{g|eo|tie|t=vir}}
}}
2f664u16dxghjn56rfe6q5dp1dnrp4o
have
0
25539
6241791
6116711
2026-07-12T13:31:48Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker */
6241791
wikitext
text/x-wiki
== {{ziman|da}} ==
=== Lêker ===
{{lêker|da}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
#* {{bêmînak|da}}
=== Çavkanî ===
{{rûpela wergerê|da|hebûn}}
== {{ziman|en}} ==
=== Bilêvkirin ===
:{{ku-tîp|hev}}
* {{deng|en|en-us-have.ogg|dever=DYA}}
* {{deng|en|En-uk-to have.ogg|dever=QY}}
* {{deng|en|EN-AU ck1 have.ogg|dever=Awistralya}}
* {{deng|en|LL-Q1860 (eng)-Nattes à chat-have.wav|Deng|dever=}}
* {{deng|en|LL-Q1860 (eng)-Back ache-have.wav|Deng|dever=London, QY}}
=== Lêker ===
{{en-tewîn-lk|form=awarte|n3y=has|b=had|pb=had|pn=having}}
{{lêker|en}}
# [[hebûn]], [[heyîn]]
# Dêran
#: {{mk|en|I '''have''' two brothers.|Min du bira hene.|rêz=1}}
#: I have two brothers.- Ez du birayan didêrim.
# [[xwestin]], [[viyan]], [[hez|hez kirin]]
#: {{mk|en|What would you like to '''have''' for lunch?|Tu dixwazî çi firavînê bixwî?}}
# [[xwedî bûn]]
#: {{mk|en|I '''have''' important work for you.|Ez xwedîyê karek muhim im ji bo te.}}
==== Jê ====
* {{g|en|have to}}
== {{ziman|lad}} ==
=== Navdêr ===
{{navdêr|lad|z=m}}
# {{mijar|lad|heywan}} {{g|ku|teyr}}, {{g|ku|firinde}}, {{g|ku|balinde}}
#* {{bênimûne|lad}}
=== Çavkanî ===
{{rûpela wergerê|lad|teyr}}
== {{ziman|nb}} ==
=== Navdêr ===
{{navdêr|nb|z=n}}
# {{g|ku|baxçe}}
#* {{bêmînak|nb}}
=== Çavkanî ===
{{rûpela wergerê|nb|baxçe}}
2gt2nic6dfeovmhgwd8ksb4s1jbp3s7
6241798
6241791
2026-07-12T13:44:55Z
Wikihez
7344
@[[User:Kewkûrk]] wextê mane eynî be, di eynî rêzê de binivîse, ji kerema xwe ([[m:Special:MyLanguage/User:Jon Harald Søby/diffedit|diffedit]])
6241798
wikitext
text/x-wiki
== {{ziman|da}} ==
=== Lêker ===
{{lêker|da}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
#* {{bêmînak|da}}
=== Çavkanî ===
{{rûpela wergerê|da|hebûn}}
== {{ziman|en}} ==
=== Bilêvkirin ===
:{{ku-tîp|hev}}
* {{deng|en|en-us-have.ogg|dever=DYA}}
* {{deng|en|En-uk-to have.ogg|dever=QY}}
* {{deng|en|EN-AU ck1 have.ogg|dever=Awistralya}}
* {{deng|en|LL-Q1860 (eng)-Nattes à chat-have.wav|Deng|dever=}}
* {{deng|en|LL-Q1860 (eng)-Back ache-have.wav|Deng|dever=London, QY}}
=== Lêker ===
{{en-tewîn-lk|form=awarte|n3y=has|b=had|pb=had|pn=having}}
{{lêker|en}}
# [[hebûn]], [[dêran]]
#: {{nm|en|I '''have''' two brothers.|Min du bira hene. / Ez du birayan didêrim|rêz=1}}
# [[xwestin]], [[viyan]], [[hez|hez kirin]]
#: {{mk|en|What would you like to '''have''' for lunch?|Tu dixwazî çi firavînê bixwî?}}
# [[xwedî bûn]]
#: {{mk|en|I '''have''' important work for you.|Ez xwedîyê karek muhim im ji bo te.}}
==== Jê ====
* {{g|en|have to}}
== {{ziman|lad}} ==
=== Navdêr ===
{{navdêr|lad|z=m}}
# {{mijar|lad|heywan}} {{g|ku|teyr}}, {{g|ku|firinde}}, {{g|ku|balinde}}
#* {{bênimûne|lad}}
=== Çavkanî ===
{{rûpela wergerê|lad|teyr}}
== {{ziman|nb}} ==
=== Navdêr ===
{{navdêr|nb|z=n}}
# {{g|ku|baxçe}}
#* {{bêmînak|nb}}
=== Çavkanî ===
{{rûpela wergerê|nb|baxçe}}
119dk9glgcdptsfxznx7dd5vcg2egrr
6241799
6241798
2026-07-12T13:45:42Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241799
wikitext
text/x-wiki
== {{ziman|da}} ==
=== Lêker ===
{{lêker|da}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
#* {{bêmînak|da}}
=== Çavkanî ===
{{rûpela wergerê|da|hebûn}}
== {{ziman|en}} ==
=== Bilêvkirin ===
:{{ku-tîp|hev}}
* {{deng|en|en-us-have.ogg|dever=DYA}}
* {{deng|en|En-uk-to have.ogg|dever=QY}}
* {{deng|en|EN-AU ck1 have.ogg|dever=Awistralya}}
* {{deng|en|LL-Q1860 (eng)-Nattes à chat-have.wav|Deng|dever=}}
* {{deng|en|LL-Q1860 (eng)-Back ache-have.wav|Deng|dever=London, QY}}
=== Lêker ===
{{en-tewîn-lk|form=awarte|n3y=has|b=had|pb=had|pn=having}}
{{lêker|en}}
# [[hebûn]], [[dêran]]
#: {{nm|en|I '''have''' two brothers.|Min du bira hene. / Ez du birayan didêrim.|rêz=1}}
# [[xwestin]], [[viyan]], [[hez|hez kirin]]
#: {{mk|en|What would you like to '''have''' for lunch?|Tu dixwazî çi firavînê bixwî?}}
# [[xwedî bûn]]
#: {{mk|en|I '''have''' important work for you.|Ez xwedîyê karek muhim im ji bo te.}}
==== Jê ====
* {{g|en|have to}}
== {{ziman|lad}} ==
=== Navdêr ===
{{navdêr|lad|z=m}}
# {{mijar|lad|heywan}} {{g|ku|teyr}}, {{g|ku|firinde}}, {{g|ku|balinde}}
#* {{bênimûne|lad}}
=== Çavkanî ===
{{rûpela wergerê|lad|teyr}}
== {{ziman|nb}} ==
=== Navdêr ===
{{navdêr|nb|z=n}}
# {{g|ku|baxçe}}
#* {{bêmînak|nb}}
=== Çavkanî ===
{{rûpela wergerê|nb|baxçe}}
jj8c6e6hh5z53lqj53dy6989v4h920v
di-
0
25928
6241927
6132441
2026-07-12T22:52:01Z
Kurdanparez
14556
Teorî
6241927
wikitext
text/x-wiki
{{bnr-h|di|di-|dî|dı}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Pêşgir ===
{{pêşgir|ku}}
# [[nîşan]]a [[dema niha]] di [[hevok]]ên [[erênî]] de
#:''Ez '''diçim'''. <br>Ew '''dibêjin''', <br>Hûn '''dikin'''.''
# [[nîşan]]a [[berdewamî|berdewamiyê]] di [[demên borî]] de
#: ''Ez hingê '''diçûm''' mala wan. <br>Wî wê salê li [[zanko|zankoyê]] '''dixwend'''. <br>Wan hê '''nedizanî''' ku em hatine.''
==== Herwiha ====
* [[e(d)-]]
==== Bide ber ====
{{stûn|
* [[bi-]]
* [[dê]]
* [[na-]]
* [[ne-]]
* [[ni-]]
}}
==== Etîmolojî ====
Bi devokî herwiha [[t-]] (Behdînan) yan [[de-]] (Xorasan), [[hevreh]]ên soranî [[de-]] û (bi helîna D-yê) [[e-]], [[kurdiya başûrî]] [[e-]], belûçî [[-e]]... Ji [[di]]; wek '''di'''-çim = '''di''' çûnê de me, di karê çûyîniyê de me. Gengazkî pêşî bo dema niha a berdewam bi kar dihat (wek tirkî ''yapmaktayım'', îngilîzî ''i am (at) doing''). Bide ber {{hv|zza|-en}}.
Li gorî Stilo, dibe ku di-, de-, ed- û formên din hevrehên {{hv|tly|at-}}, ''ad-'', ''ar-'', ''an-'' (''Vefşî'') hem jî hin zimanên îraniya başûr-rojavayî ne, lê ev xuya neye. Ew dibêje: "Extending to the northwest, it is even plausible that the Kurdish tense-aspect markers (N. Kurdish) di- ~ da- ~ t- and (C. Kurdish) a- ~ da- are also this same morpheme but this interpretation is far from certain."<ref>Stilo, D., (2007) Isfahan xxi. PROVINCIAL DIALECTS https://www.iranicaonline.org/articles/isfahan-xxi-provincial-dialects/</ref>
==== Bi zaravayên kurdî ====
* {{Z|ckb}}: {{W-|ckb|de-|sc=Latn}}, {{W-|ckb|e-|sc=Latn}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
===Çavkanî===
{{çavkanî}}
== {{ziman|en}} ==
=== Pêşgir ===
{{pêşgir|en}}
# [[dî-]], [[du-]]
==== Jê ====
{{pêşgirbibîne|en}}
{{kol3|en
|dicotyledon
|digamma
|diglot
|digraph
|dioxide
|dipole
|disulfate
|disyllable
|dizygotic
}}
k4t1s2ufv0o6c314991tcxhp94xlaln
e-
0
27608
6241876
6132761
2026-07-12T21:25:38Z
Wikihez
7344
/* {{ziman|en}} */
6241876
wikitext
text/x-wiki
{{binêre herwiha/e}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Pêşgir ===
{{pêşgir|ku}}
# [[kurte]]ya [[elektronîk]]ê
#: ''[[e-poste]], [[e-mail]]''
# [[pêşgir]]ek e ku pê hin [[peyv]]ên [[nû]] ji yên [[heyî]] tên çêkirin
#: ''[[evîn]] (e- + [[vîn]]), <br>[[eware]] (e- + [[war]] + [[-e]]''
# (''[[devokî]]: [[Anadoliya Navîn]]'') [[di-]]: e-kim (di-kim), [[e-kî]] (dikî), [[e-kin]] (di-kin)-
== {{ziman|ckb}} ==
=== Pêşgir ===
{{pêşgir|ckb|sc=Latn}}
# [[di-]]
#: ''min '''e'''çim'' (ez '''di'''çim), <br>''Ewan ne-'''e'''wut'' (wan ne'''di'''got)
==== Herwiha ====
* {{g|ckb|de-|sc=Latn}}
== {{ziman|en}} ==
=== Pêşgir ===
{{pêşgir|en}}
# [[derve]]
# {{maneid|en|dîjîtal}} Ji [[bo]] [[tişt]]ên [[elektronî]] bi [[gelemperî]] bo [[internet]]ê.
# bo [[rewş]]ên [[lezgîn]]
==== Herwiha ====
{{kol3|en
|de-
|ef-
|ex-
}}
==== Jê ====
{{paşgirbibîne|en|id=dijîtal}}
== {{ziman|la}} ==
=== Pêşgir ===
{{pêşgir|la}}
# [[derve]]
==== Jê ====
{{kol3|la
|ebibo
|edormio
|elingo
}}
5sfn2x478vuia2im3wzwax2dg3lquhx
6241877
6241876
2026-07-12T21:25:58Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241877
wikitext
text/x-wiki
{{binêre herwiha/e}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Pêşgir ===
{{pêşgir|ku}}
# [[kurte]]ya [[elektronîk]]ê
#: ''[[e-poste]], [[e-mail]]''
# [[pêşgir]]ek e ku pê hin [[peyv]]ên [[nû]] ji yên [[heyî]] tên çêkirin
#: ''[[evîn]] (e- + [[vîn]]), <br>[[eware]] (e- + [[war]] + [[-e]]''
# (''[[devokî]]: [[Anadoliya Navîn]]'') [[di-]]: e-kim (di-kim), [[e-kî]] (dikî), [[e-kin]] (di-kin)-
== {{ziman|ckb}} ==
=== Pêşgir ===
{{pêşgir|ckb|sc=Latn}}
# [[di-]]
#: ''min '''e'''çim'' (ez '''di'''çim), <br>''Ewan ne-'''e'''wut'' (wan ne'''di'''got)
==== Herwiha ====
* {{g|ckb|de-|sc=Latn}}
== {{ziman|en}} ==
=== Pêşgir ===
{{pêşgir|en}}
# [[derve]]
# {{maneid|en|dîjîtal}} Ji [[bo]] [[tişt]]ên [[elektronî]] bi [[gelemperî]] bo [[internet]]ê.
# bo [[rewş]]ên [[lezgîn]]
==== Herwiha ====
{{kol3|en
|de-
|ef-
|ex-
}}
==== Jê ====
{{pêşgirbibîne|en}}
{{pêşgirbibîne|en|id=dijîtal}}
== {{ziman|la}} ==
=== Pêşgir ===
{{pêşgir|la}}
# [[derve]]
==== Jê ====
{{kol3|la
|ebibo
|edormio
|elingo
}}
2lv1ir3wj6sfdlqquc06hrblfkm44c2
amay
0
47232
6241909
5915956
2026-07-12T22:01:52Z
Kurdanparez
14556
6241909
wikitext
text/x-wiki
== {{ziman|hac}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
=== Lêker ===
{{lêker|hac|sc=Latn}}
# {{hac-Arab|ئامای}}
#* {{bêmînak|hac}}
== {{ziman|mba}} ==
=== Navdêr ===
{{navdêr|mba}}
# {{f|mba|malbat}} [[bav#ku|bav]], [[bab#ku|bab]]
#* {{bêmînak|mba}}
== {{ziman|hil}} ==
=== Navdêr ===
{{navdêr|hil}}
# {{f|hil|malbat}} [[bav#ku|bav]], [[bab#ku|bab]]
#* {{bêmînak|hil}}
069iek3yccldw9s5oelp0nuy6xwqsxh
kerdey
0
47263
6241830
5076924
2026-07-12T16:22:43Z
Kurdanparez
14556
6241830
wikitext
text/x-wiki
== {{ziman|hac}} ==
=== Lêker ===
{{lêker|hac|sc=Latn}}
# {{hac-Arab|کەردەی}}
#: ''Gim '''kerdey''''' (winda kirin, [[hinda kirin]], [[berze kirin]], gum kirin)
du78yppaicv6tito9uqmm98rv1t6hy0
amaene
0
47435
6241916
6069776
2026-07-12T22:14:41Z
Kurdanparez
14556
Standardê Wikiferhengê alfabeya Vate ye, versîyonê bi alfabeya Jacobsonê jî mimkin e, ema gerek format bêlî bibe
6241916
wikitext
text/x-wiki
== {{ziman|zza}} ==
=== Lêker ===
{{lêker|zza|c=x-ngh}}
# [[hatin]]
#* {{bêmînak|zza}}
==== Herwiha ====
{{kol3|zza
|ameyene
|ameyine
}}
==== Tewandin ====
* Dema niha: y'''en'''-
* Dema borî: am'''a'''-
;Rıstımê wextan
{|{{prettytable}}
|-bgcolor='#COFOFO'
!ristimê wextê nikay
!ristimê wextê verî
!ristimê modusê waştene
|-
|y'''en'''-||am'''a'''-||b'''êr'''-||
|-
|}
;Wextê nikay (''present'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''continuative''
!''subjunctive''
!''imperative''
|-
|''ez'' yen'''an'''||''ezo'' yen'''an'''||''ez'' bêr'''an'''||-||
|-
|''ti'' yen'''ay'''||''tiyay'' yen'''ay'''||''ti'' bêr'''ê'''||''ti'' b'''ê'''||
|-
|''o'' yen'''o'''||''oyo'' yen'''o'''||''o'' bêr'''o'''||''o'' bêr'''o'''||
|-
|''a'' yen'''a'''||''awa'' yen'''a'''||''a'' bêr'''o'''||''a'' bêr'''o'''||
|-
|''ma'' yen'''îme'''||''mao'' yen'''îme'''||''ma'' bêr'''îme'''||''ma'' bêr'''îme'''||
|-
|''şima'' yen'''ê'''||''şimaê'' yen'''ê'''||''şima'' bêr'''ê'''||''şima'' bêr'''ê'''||
|-
|''ê'' yen'''ê'''||''êyê'' yen'''ê'''||''ê'' bêr'''ê'''||''ê'' bêr'''ê'''||
|-
|}
;Wextê verî (''preterite'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''continuative''
|-
|''ez'' am'''an'''||''ezo'' am'''an'''||
|-
|''ti'' am'''ay'''||''tiyay'' am'''ay'''||
|-
|''o'' am'''e'''||''oyo'' am'''e'''||
|-
|''a'' am'''ê'''||''awa'' am'''ê'''||
|-
|''ma'' ame'''yme'''||''mao'' ame'''yme'''||
|-
|''şima'' ame'''y'''||''şimaê'' ame'''y'''||
|-
|''ê'' ame'''y'''||''êyê'' ame'''y'''||
|-
|}
;Wextê verî -gumankerdene- (''perfect'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''continuative''
|-
|''ez'' am'''an'''||''ezo'' am'''an'''||
|-
|''ti'' am'''ay'''||''tiyay'' am'''ay'''||
|-
|''o'' am'''o'''||''oyo'' am'''o'''||
|-
|''a'' am'''a'''||''awa'' am'''a'''||
|-
|''ma'' ame'''yme'''||''mao'' ame'''yme'''||
|-
|''şima'' am'''ê'''||''şimaê'' am'''ê'''||
|-
|''ê'' am'''ê'''||''êyê'' am'''ê'''||
|-
|}
;Wextê verî -raverberdene- (''imperfect'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''subjunctive''
|-
|''ez'' am'''êne'''||''ez'' bîam'''êne'''||
|-
|''ti'' am'''êne'''||''ti'' bîam'''êne'''||
|-
|''o'' am'''êne'''||''o'' bîam'''êne'''||
|-
|''a'' am'''êne'''||''a'' bîam'''êne'''||
|-
|''ma'' am'''êne'''||''ma'' bîam'''êne'''||
|-
|''şima'' am'''êne'''||''şima'' bîam'''êne'''||
|-
|''ê'' am'''êne'''||''ê'' bîam'''êne'''||
|-
|}
;Wextê verî ''ra raver'' (''pluperfect'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
|-
|''ez'' ame '''bî'''||
|-
|''ti'' ame '''bî'''||
|-
|''o'' ame '''bî'''||
|-
|''a'' ame '''bî'''||
|-
|''ma'' ame '''bî'''||
|-
|''şima'' ame '''bî'''||
|-
|''ê'' ame '''bî'''||
|-
|}
;''Participium''
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''participium''
!nerî
!ma[y]kî
!xeylê
|-
|''agentive''||ama'''oẍ'''||ama'''oẍe'''||ama'''oẍi'''||
|-
|''preterital''||-||-||-||
|-
|}
6hr1lmj19yfxo79ojfgtp7xkhg1deg8
6241919
6241916
2026-07-12T22:16:23Z
Kurdanparez
14556
6241919
wikitext
text/x-wiki
== {{ziman|zza}} ==
=== Lêker ===
{{lêker|zza|c=x-ngh}}
# [[hatin]]
#* {{bêmînak|zza}}
==== Herwiha ====
{{kol3|zza
|amayene
|ameyene
|ameyine
}}
==== Tewandin ====
* Dema niha: y'''en'''-
* Dema borî: am'''a'''-
;Rıstımê wextan
{|{{prettytable}}
|-bgcolor='#COFOFO'
!ristimê wextê nikay
!ristimê wextê verî
!ristimê modusê waştene
|-
|y'''en'''-||am'''a'''-||b'''êr'''-||
|-
|}
;Wextê nikay (''present'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''continuative''
!''subjunctive''
!''imperative''
|-
|''ez'' yen'''an'''||''ezo'' yen'''an'''||''ez'' bêr'''an'''||-||
|-
|''ti'' yen'''ay'''||''tiyay'' yen'''ay'''||''ti'' bêr'''ê'''||''ti'' b'''ê'''||
|-
|''o'' yen'''o'''||''oyo'' yen'''o'''||''o'' bêr'''o'''||''o'' bêr'''o'''||
|-
|''a'' yen'''a'''||''awa'' yen'''a'''||''a'' bêr'''o'''||''a'' bêr'''o'''||
|-
|''ma'' yen'''îme'''||''mao'' yen'''îme'''||''ma'' bêr'''îme'''||''ma'' bêr'''îme'''||
|-
|''şima'' yen'''ê'''||''şimaê'' yen'''ê'''||''şima'' bêr'''ê'''||''şima'' bêr'''ê'''||
|-
|''ê'' yen'''ê'''||''êyê'' yen'''ê'''||''ê'' bêr'''ê'''||''ê'' bêr'''ê'''||
|-
|}
;Wextê verî (''preterite'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''continuative''
|-
|''ez'' am'''an'''||''ezo'' am'''an'''||
|-
|''ti'' am'''ay'''||''tiyay'' am'''ay'''||
|-
|''o'' am'''e'''||''oyo'' am'''e'''||
|-
|''a'' am'''ê'''||''awa'' am'''ê'''||
|-
|''ma'' ame'''yme'''||''mao'' ame'''yme'''||
|-
|''şima'' ame'''y'''||''şimaê'' ame'''y'''||
|-
|''ê'' ame'''y'''||''êyê'' ame'''y'''||
|-
|}
;Wextê verî -gumankerdene- (''perfect'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''continuative''
|-
|''ez'' am'''an'''||''ezo'' am'''an'''||
|-
|''ti'' am'''ay'''||''tiyay'' am'''ay'''||
|-
|''o'' am'''o'''||''oyo'' am'''o'''||
|-
|''a'' am'''a'''||''awa'' am'''a'''||
|-
|''ma'' ame'''yme'''||''mao'' ame'''yme'''||
|-
|''şima'' am'''ê'''||''şimaê'' am'''ê'''||
|-
|''ê'' am'''ê'''||''êyê'' am'''ê'''||
|-
|}
;Wextê verî -raverberdene- (''imperfect'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
!''subjunctive''
|-
|''ez'' am'''êne'''||''ez'' bîam'''êne'''||
|-
|''ti'' am'''êne'''||''ti'' bîam'''êne'''||
|-
|''o'' am'''êne'''||''o'' bîam'''êne'''||
|-
|''a'' am'''êne'''||''a'' bîam'''êne'''||
|-
|''ma'' am'''êne'''||''ma'' bîam'''êne'''||
|-
|''şima'' am'''êne'''||''şima'' bîam'''êne'''||
|-
|''ê'' am'''êne'''||''ê'' bîam'''êne'''||
|-
|}
;Wextê verî ''ra raver'' (''pluperfect'')
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''indicative''
|-
|''ez'' ame '''bî'''||
|-
|''ti'' ame '''bî'''||
|-
|''o'' ame '''bî'''||
|-
|''a'' ame '''bî'''||
|-
|''ma'' ame '''bî'''||
|-
|''şima'' ame '''bî'''||
|-
|''ê'' ame '''bî'''||
|-
|}
;''Participium''
{|{{prettytable}}
|-bgcolor='#COFOFO'
!''participium''
!nerî
!ma[y]kî
!xeylê
|-
|''agentive''||ama'''oẍ'''||ama'''oẍe'''||ama'''oẍi'''||
|-
|''preterital''||-||-||-||
|-
|}
====Etîmolojî====
Hevreha {{hv|hac|ئامای}}, {{hv|ku|hatin}}.
8rkkloboejtl6oid43v1yb9yfmkm9vz
vewre
0
49180
6241845
6069858
2026-07-12T17:31:54Z
Kurdanparez
14556
6241845
wikitext
text/x-wiki
== {{ziman|zza}} ==
=== Navdêr ===
{{navdêr|zza|z=m}}
# [[berf]], [[befr]]
#* {{jêder-malper|zza|jêgirtin=Vizêr Kurdistanê Vakurî de, şaristanê Hekarya de '''vewre''' varaye. Yew camêrdêkê kalî va, "Yeno vîrê mi, serra 1948 de, aşma nîsane de 1 metre '''vewra''' varaybî."|werger=Duhî li Kurdistana Bakur, li wîlayeta Hekariyê berf barî. Camêrekî pîr got: "Tê bîra min, sala 1948ê meha nîsanê metreyek befr barîbû.|malper=Netkurd.com|dîrok=4/2008}}
==== Herwiha ====
{{kol3|zza
|vore
|verf
}}
====Etîmolojî====
Hevreha {{hv|hac|وەروە}}, {{hv|ku|berf}}.
[[Kategorî:Peyvên zazakî bi paşgira -e (mêker)]]
1ai4k5rqsyagdb1b4x62ke82cjd0mck
6241846
6241845
2026-07-12T17:33:54Z
Kurdanparez
14556
6241846
wikitext
text/x-wiki
== {{ziman|zza}} ==
===Bilêvkirin===
* {{zza-IPA}}
* {{zza-kîte}}
=== Navdêr ===
[[Wêne:Düsseldorf Hofgarten 2009.jpg|thumb|rast|Vewre.]]
{{navdêr|zza|z=m}}
# [[berf]], [[befr]]
#* {{jêder-malper|zza|jêgirtin=Vizêr Kurdistanê Vakurî de, şaristanê Hekarya de '''vewre''' varaye. Yew camêrdêkê kalî va, "Yeno vîrê mi, serra 1948 de, aşma nîsane de 1 metre '''vewra''' varaybî."|werger=Duhî li Kurdistana Bakur, li wîlayeta Hekariyê berf barî. Camêrekî pîr got: "Tê bîra min, sala 1948ê meha nîsanê metreyek befr barîbû.|malper=Netkurd.com|dîrok=4/2008}}
==== Herwiha ====
{{kol3|zza
|vore
|verf
}}
====Tewandin====
{{zza-tewîn-nav|z=m}}
====Etîmolojî====
Hevreha {{hv|hac|وەروە}}, {{hv|ku|berf}}.
[[Kategorî:Peyvên zazakî bi paşgira -e (mêker)]]
19h0n9v8vz794fsj5s8ghfg248mj6my
avoir
0
51006
6241792
6040092
2026-07-12T13:32:53Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker */
6241792
wikitext
text/x-wiki
== {{ziman|fro}} ==
=== Lêker ===
{{lêker|fro}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
#* {{bêmînak|fro}}
=== Çavkanî ===
{{rûpela wergerê|fro|hebûn}}
== {{ziman|fr}} ==
=== Bilêvkirin ===
: {{ku-tîp|avwaẍ}}
* {{deng|fr|LL-Q150 (fra)-GrandCelinien-avoir.wav|Deng|dever=Parîs, Fransa}}
* {{deng|fr|LL-Q150 (fra)-Pamputt-avoir.wav|Deng|dever=Manche, Fransa}}
* {{deng|fr|LL-Q150 (fra)-Poslovitch-avoir.wav|Deng|dever=Cornimont, Fransa}}
* {{deng|fr|LL-Q150 (fra)-DSwissK-avoir.wav|Deng|dever=Valais, Swîsre}}
* {{deng|fr|LL-Q150 (fra)-Jérémy-Günther-Heinz Jähnick-avoir.wav|Deng|dever=Somain, Fransa}}
=== Lêker ===
{{lêker|fr}}
# [[hebûn]]
# dêran
#* {{bêmînak|fr}}
0okmb50yk8m4anb01iv342xzf19k0ij
6241793
6241792
2026-07-12T13:33:30Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker */
6241793
wikitext
text/x-wiki
== {{ziman|fro}} ==
=== Lêker ===
{{lêker|fro}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
# dêran
#* {{bêmînak|fro}}
=== Çavkanî ===
{{rûpela wergerê|fro|hebûn}}
== {{ziman|fr}} ==
=== Bilêvkirin ===
: {{ku-tîp|avwaẍ}}
* {{deng|fr|LL-Q150 (fra)-GrandCelinien-avoir.wav|Deng|dever=Parîs, Fransa}}
* {{deng|fr|LL-Q150 (fra)-Pamputt-avoir.wav|Deng|dever=Manche, Fransa}}
* {{deng|fr|LL-Q150 (fra)-Poslovitch-avoir.wav|Deng|dever=Cornimont, Fransa}}
* {{deng|fr|LL-Q150 (fra)-DSwissK-avoir.wav|Deng|dever=Valais, Swîsre}}
* {{deng|fr|LL-Q150 (fra)-Jérémy-Günther-Heinz Jähnick-avoir.wav|Deng|dever=Somain, Fransa}}
=== Lêker ===
{{lêker|fr}}
# [[hebûn]]
# dêran
#* {{bêmînak|fr}}
to2l88gkmfqesyh70djib4q4r81hq9a
tevşo
0
53821
6241947
5931919
2026-07-13T11:22:21Z
~2026-39502-46
15136
Werger: +fînî : [[vasara]] (bi alîkarî)
6241947
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Navdêr ===
{{navdêr|ku|z=n}}
# Amûrê ku bizmar dikute yan jî dikişîne
#* {{bêmînak|ku}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W-|de|Dachsbeil}}
* {{Z|fa}}: {{W+|fa|تیشه}}
* {{Z|fi}}: {{W+|fi|vasara}}
* {{Z|en}}: {{W+|en|adze}}
* {{Z|tr}}: {{W+|tr|kerki}}, {{W+|tr|keser}}
{{werger-bin}}
t15f1245f7a16lrrfdhoscwbgbe4em8
dêran
0
54284
6241766
6232495
2026-07-12T12:46:26Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +îngilîzî : [[have]] (bi alîkarî)
6241766
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|en}}: {{W+|en|have}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
4s9u9891xnkwogl98nfx618k2khwkmn
6241767
6241766
2026-07-12T12:47:24Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +tirkî : [[sahip olmak]]; +fransî : [[avoir]] (bi alîkarî)
6241767
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|fr}}: {{W+|fr|avoir}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
3ykvcskrt3eqwev68r9jxacmefh99bb
6241768
6241767
2026-07-12T12:47:41Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +fransî : [[détenir]] (bi alîkarî)
6241768
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
sudk2hvo1gojuln33zvxwtqf0pyjcx0
6241769
6241768
2026-07-12T12:47:53Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +fransî : [[posséder]] (bi alîkarî)
6241769
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
amnp2ng96jkwd6kwa6tf1l19mn1p621
6241770
6241769
2026-07-12T12:48:30Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +farisî : [[داشتن]] (bi alîkarî)
6241770
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
90926j59524wufp0mm817v705fr38vh
6241772
6241770
2026-07-12T12:49:07Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +almanî : [[haben]] (bi alîkarî)
6241772
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
7gyx9wygsvgjasyefhz46h0dy4zg4ha
6241773
6241772
2026-07-12T12:50:11Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +spanî : [[tener]] (bi alîkarî)
6241773
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
0l6r69e4wugy35warlux2hyfpdonao5
6241774
6241773
2026-07-12T12:51:42Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +portugalî : [[ter]] (bi alîkarî)
6241774
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
9me023kb19jauo666zr5z66d1ngza36
6241775
6241774
2026-07-12T12:52:17Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +katalanî : [[tenir]] (bi alîkarî)
6241775
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
1rr3x3wgmbmpaw3z1iu4awaj8brbubd
6241776
6241775
2026-07-12T12:59:52Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +yûnanî : [[να έχω]] (bi alîkarî)
6241776
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{ku-tewîn-reh|form=gh|niha=dêr|borî=dêrî}}
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
tusz7akpmkf4wxzwk4gbpu7ggrbxhs7
6241781
6241776
2026-07-12T13:09:50Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker 1 */
6241781
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
056486cb6uv378x38xgia0gzl5dx387
6241782
6241781
2026-07-12T13:17:13Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker 1 */
6241782
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
pndulxgbcnm0c0r6hftn87niuezh7kf
6241783
6241782
2026-07-12T13:21:26Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker 1 */
6241783
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
8fghdc08n2ro23x7a7xed4jhz2fxv1t
6241785
6241783
2026-07-12T13:23:53Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker 1 */ Min agahî zêde kirin li gotarê
6241785
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
056486cb6uv378x38xgia0gzl5dx387
6241787
6241785
2026-07-12T13:26:14Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +azerî : [[sahib olmaq]] (bi alîkarî)
6241787
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|az}}: {{W-|az|sahib olmaq}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
h8qb81c9qyq1edufoaspw3nv6smppln
6241788
6241787
2026-07-12T13:27:17Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +peştûyî : [[درلودل]] (bi alîkarî)
6241788
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|az}}: {{W-|az|sahib olmaq}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|ps}}: {{W+|ps|درلودل}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
ct31wh037exll94pwujzp47wmokf8as
6241789
6241788
2026-07-12T13:28:17Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +erebî : [[أن يكون لديك]] (bi alîkarî)
6241789
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|az}}: {{W-|az|sahib olmaq}}
* {{Z|ar}}: {{W-|ar|أن يكون لديك}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|ps}}: {{W+|ps|درلودل}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
rv3lgosjty05ynpp1cp3xt0f5t67zgo
6241796
6241789
2026-07-12T13:36:37Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +rusî : [[иметь]] (bi alîkarî)
6241796
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|az}}: {{W-|az|sahib olmaq}}
* {{Z|ar}}: {{W-|ar|أن يكون لديك}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|ps}}: {{W+|ps|درلودل}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|ru}}: {{W+|ru|иметь}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
rg3et9cvebeb56kjcvvug4y6z0p86el
6241797
6241796
2026-07-12T13:37:35Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Werger: +ûkraynî : [[мати]] (bi alîkarî)
6241797
wikitext
text/x-wiki
{{bnr-h|Dêran}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{IPA|ku|/deːˈɾɑːn/}}
* {{ku-kîte}}
* {{deng|ku|LL-Q36368 (kur)-Dildadil-dêran.wav|Deng|dever=Amed}}
=== Navdêr 1 ===
{{ku-tewîn-nav|dêran|mê}}
{{navdêr|ku|z=m}}
# [[ferman]]a [[veqetandin]] û [[kuştin]] yan jî [[ceza kirin]]a [[kes]]ên ji [[reng]]ekî, ji [[eşîret]]ekê, ji [[gel]]ekî, ji [[dîn]]ekî ku ji aliyê [[hêz]]ên [[desthilatdar]] ve wek [[dijmin]] hatine [[pejirandin]]
#: {{mk|ku|'''dêran''' li fileyan rabû}}
#: {{mk|ku|'''dêran''' e li me '''dêran''' e}}
#* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Her kesê rabî di behsê carekê mehder bikit</br>Xeyr-i heftî hec '''didêrit''' belko bihtir ew sewab</br>We'de dabû dê şehîd kim wî bi şîrê xwey şerîf}}
==== Jê ====
{{stûn|
* [[dêranber]]
* [[dêranberî]]
* [[dêrander]]
* [[dêranderî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranî]]
}}
==== Werger ====
{{werger-ser}}
* {{Z|fa}}: {{W+|fa|بدبخت}}, {{W+|fa|داشتن}}, {{W|fa|بیچاره|guman=erê}}
* {{Z|en}}: {{W+|en|fanning|guman=erê}}, {{W+|en|winnowing|guman=erê}}, {{W|en|in ruins|guman=erê}}, {{W|en|ramshackle|guman=erê}}, {{W|en|ruinous|guman=erê}}, {{W|en|rundown|guman=erê}}
* {{Z|tr}}: {{W+|tr|ayrışım}}, {{W+|tr|harabe}}, {{W+|tr|harabelik}}, {{W+|tr|zavallı|guman=erê}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[jar]], [[hejar]], [[perîşan]], [[reben]], [[goyîn]], [[belingaz]], [[şepirze]], [[kepaze]]
#: {{mk|ku|dayê '''dêranê'''}}
==== Jê ====
* [[dêranî]]
* [[dêranîtî]]
* [[dêrantî]]
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Navdêr 2 ===
{{navdêr|ku|z=m}}
# [[bênder]], [[bêder]], [[berba]], [[ka]] li [[ba]] kirin, <br />[[kar]]ê bi [[ba]]yî, <br />[[tişt]]ên wek [[ka]] û [[zad]] ji hev [[veqetandin]]ê
#: {{mk|ku|Em ji '''dêranê''' dihên.}}
==== Jê ====
{{stûn|
* [[dêrangeh]]
* [[dêranî]]
* [[dêrankar]]
* [[dêrankarî]]
* [[dêranker]]
* [[dêrankerî]]
* [[dêranvan]]
* [[dêranvanî]]
}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Lêker 1 ===
{{lêker|ku|c=x-gh}}
# {{maneid|ku|hebûn}} [[hebûn]], [[heyîn]], [[xwedî]] bûn
#: {{mk|ku|Ew sê bira û du xwişkan '''didêre'''.|Wî sê bira û du xwişk hene.|birêz=1}}
==== Herwiha ====
* [[dêrandin]]
==== Nîşe ====
Gelek kêm di axivîna rojane de peyda dibe. Hevreha [[-dar]] e (ji rehê dema niha yê lêkera farisî {{g|fa|داشتن}}.
(Di paş peyvan da em paşgira -dar- pirr dibînin, ew paşgir mane û maneya xwedîbûnê dide peyvan û ji peyvan rengdêr derdikevin: mînak “birîn” birîn-dar, ango kesê/kesa ku birînê didêre an kesê/kesa ke birîna xwe heye)
==== Jê ====
* [[dêrayî]]
==== Etîmolojî ====
Ji berê {{jinûvesazî|ku|dartin}}, yeksanî farisî {{q|ku|داشتن|tr=daşten|w=*dartin, hebûn, girtin}}, dema bihûrî {{jinûvesazî|ku|dart}} û lêkereke gerrguhêz ku dikare wek {{q|ku|girtin}} jî li kar bibe.
Ji {{mîr|ine-pro|ku|*dʰer-}}, hevreha {{hv|en|firm|w=pihêt}} (<{{hv|la|firmus}}), {{q|en|throne|w=text}} (<{{hv|grc|θρόνος}}), {{hv|pal|𐫅𐫀𐫢𐫤𐫗|tr=daşten}}, {{hv|peo|𐎭𐎠𐎼𐎹𐎫𐎡𐎹|tr=dareyetî}}...
Di ti zimanek din ê kurdî de nemaye, ji bilî ku hinan (nexasma ên nêzîkê farisî wek pallewanî û hewramî) ku ''daştin'' ji farisî wergirtiye lê ew jî tenê di dema bihûrî de bi kar tê. Li deverinan di biwêjine archaic de bi kar tê wek ''guh bidêre'' (guh bide, guh bigire) û {{q|ku|çavdêrî}}; û di wêjeya klasîk de jî diyar e lê ew jî merzkirî devera xwe ye anku Botan û Badînan û hwd.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|haben}}
* {{Z|az}}: {{W-|az|sahib olmaq}}
* {{Z|ar}}: {{W-|ar|أن يكون لديك}}
* {{Z|fa}}: {{W+|fa|داشتن}}
* {{Z|fr}}: {{W+|fr|avoir}}, {{W+|fr|détenir}}, {{W+|fr|posséder}}
* {{Z|en}}: {{W+|en|have}}
* {{Z|ca}}: {{W+|ca|tenir}}
* {{Z|ps}}: {{W+|ps|درلودل}}
* {{Z|pt}}: {{W+|pt|ter}}
* {{Z|ru}}: {{W+|ru|иметь}}
* {{Z|es}}: {{W+|es|tener}}
* {{Z|tr}}: {{W+|tr|sahip olmak}}
* {{Z|uk}}: {{W+|uk|мати}}
* {{Z|el}}: {{W-|el|να έχω}}
{{werger-bin}}
=== Navdêr 3 ===
{{navdêr|ku|z=m}}
# {{bêwate}}
#: {{bêmînak}}
==== Werger ====
{{werger-ser}}
{{werger-bin}}
=== Formeke navdêrê ===
{{ku-tew-nav|sêv|mê|çemandî|binavkirî}}
{{navdêr|ku|z=m|form=erê}}
# ''Rewşa [[çemandî]] ya pirjimara a binavkirî ya'' '''{{g|ku|dêr}}'''.
==== Anagram ====
* {{anagram|ku|a=adênr|rêdan|danêr}}
slfl7ls1d3tawvulf8kq470opxjqbpl
Şablon:jêder
10
59619
6241759
6081000
2026-07-12T12:19:20Z
Wikihez
7344
6241759
wikitext
text/x-wiki
<templatestyles src="jêder/style.css"/><includeonly><span class="jegirtin-text"><!--
-->{{zim<!--
-->|1={{{1|}}}<!--
-->|2={{#if:{{{jêgirtin|{{{jg|}}}}}}<!--
-->|{{{jêgirtin|{{{jg|}}}}}}<!--
-->|{{reng2|red<!--
-->|'''Divê {{param2|1}} "koda zimanî", {{param2|2}} "çavkanî", {{param2|jêgirtin}} "nivîsa jêgirtinê", {{param2|url}} "lînka çavkaniyê" be!'''<!--
-->}}<!--
-->{{kategorî|Şablon:jêder parametre duyem kêm e}}<!--
-->}}<!--
-->|sc={{{sc|}}}<!--
-->}}<!--
--></span><!-- Jêgirtin xilas bû niha jêder:
--><span class="jeder" style="font-size: 0.85em"><!--
--> — (<!-- Jêderê vekir
-->{{#if:{{{2|}}}|-{{{{2|}}}}-<!-- jêder hat zêdekirin. Ger tinebe:
-->|{{reng2|red|'''Divê {{param2|1}} "koda zimanî", {{param2|2}} "çavkanî", {{param2|jêgirtin}} "nivîsa jêgirtinê", {{param2|url}} "lînka çavkaniyê" be!'''}}<!--
-->{{kategorî|Şablon:jêder parametre duyem kêm e}}<!--
-->}}<!--
-->{{#if:{{{url|}}}<!--
-->| →<span class="plainlinks"> [{{{url|}}} here lînkê]</span> {{#if:{{{arşîv|}}}|<nowiki>[</nowiki><span class="plainlinks">[{{{arşîv|}}} arşîv]</span><nowiki>]</nowiki>|[<span class="plainlinks">[https://web.archive.org/{{{url}}} arşîv]</span>]}}<!--
-->}}<!--
-->)</span><!--jêderê girt
-->{{#if:{{{tr|}}}<!-- Heke translîterasyonek hebe binivîse:
-->|#*:{{#ifeq:{{{sc|}}}|ku-Arab|{{nekuarab|{{{tr|}}}}}|{{{tr|}}}}}<!--
-->|{{#ifeq:{{{sc|}}}|ku-Arab|#*:{{nekuarab|{{ckb-translit|{{{jg|{{{jêgirtin|}}}}}}}}}} }}}}<!--
-->{{#ifeq:{{{1|}}}|ku||<!-- Jêgirtin heye lê ziman ne kurmancî ye hingê wergerê binivîse:
-->{{#if:{{{werger|{{{w|{{{tercime|{{{t|}}}}}}}}}}}}<!-- wergerê binivîse:
-->|{{#if:{{{tr|}}}<!--
-->|#*::<!--
-->|#*:<!--
-->}}<!--
-->{{{werger|{{{w|{{{tercime|{{{t|}}}}}}}}}}}}<!-- werger hatiye nivîsin. Ger werger tinebe:
-->|{{#if:{{{tr|}}}<!-- tr heye loma li gorî wê di destpêkê de valahî bi kar bîne.
-->|#*::<!--
-->|#*:<!--
-->}}<!--
-->{{werger?|{{{1|}}}}}<!--
-->}}<!--
-->}}<!--
-->{{#if:{{{nekat|}}}||{{kategorî|Jêgirtin bi {{nav ziman|{{{1}}}}}}}}}</includeonly><!--
##Tiştên ji bo MediaWiki:Gadget-wikt.add-examples
--><span class="example"><!--
--><bdi lang="{{{1|}}}" style="display: none"><!-- Balise de marquage pour le gadget [[MediaWiki:Gadget-wikt.add-examples]], ne pas retirer ! --></bdi></span><!--
--><noinclude>
[[Kategorî:Çavkanî|{{PAGENAME}}]]
{{belgekirin}}
</noinclude>
ep6k8ktzixdxlaebuj4sov7itvea5dc
sahip olmak
0
160949
6241795
4599423
2026-07-12T13:34:50Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker */
6241795
wikitext
text/x-wiki
== {{ziman|tr}} ==
=== Lêker ===
{{lêker|tr}}
# [[bûn xweyî]], [[bûn xwedî]]
# dêran
k4n4smcpdavy6xm6i0it8hch98pm10a
yardım etmek
0
170986
6241809
4602262
2026-07-12T14:02:29Z
~2026-39288-16
15131
/* Lêker */
6241809
wikitext
text/x-wiki
== {{ziman|tr}} ==
=== Lêker ===
{{lêker|tr}}
# alî (yekî) kirin, [[talî kirin]], [[alîkarî kirin]], [[alîkariya (yekî) kirin]], [[alî kirin]], alîkarî pê re kirin, [[komek dan]], [[piştin kirin]]
b0nodb3ss2p4dfsyvow0i4kf6aezwsv
îmla
0
261279
6241937
4586609
2026-07-12T23:36:13Z
Wikihez
7344
([[Bikarhêner:Wikihez/newentrywiz.js|NEC]]) +ku:navdêr: Guhartoyeke [[imla]]
6241937
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{ku-tewîn-nav|îmla|mê}}
{{navdêr|ku|z=m}}
# {{guharto|ku|imla}}
sfvkkstel4y0fu2czhqq6tvu6u5hrk9
xwedênenas
0
266588
6241946
5774282
2026-07-13T05:46:34Z
~2026-39487-86
15132
Werger: +almanî : [[Atheist]] (bi alîkarî)
6241946
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku|z=mn}}
# [[bêdîn]], [[bêbawer]]<ref>https://web.archive.org/web/20160305060132/https://rojbas5.files.wordpress.com/2012/05/ferhenga-kamc3aaran.pdf Ferhenga Kamêran</ref>, yê ku Xwedê ne [[niyas]]e
==== Etîmolojî ====
* [[xwedê]] + [[ne]] + [[nas]]
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Heide}} {{n}}, {{W+|de|Atheist}}
* {{Z|fa}}: {{W+|fa|خدا نشناس}}, {{W-|fa|بی دین}}, {{W+|fa|کافر}}, {{W+|fa|بتپرست|guman=erê}}, {{W+|fa|منکر|guman=erê}}
* {{Z|en}}: {{W+|en|disbeliever}}, {{W+|en|unbeliever|guman=erê}}
* {{Z|tr}}: {{W+|tr|kâfir}}, {{W+|tr|tanrıtanımaz}}, {{W+|tr|allahsız}}, {{W+|tr|ateist}}, {{W+|tr|mülhit}}, {{W+|tr|münkir}}, {{W-|tr|allahtan korkmaz|guman=erê}}, {{W+|tr|dinsiz|guman=erê}}
{{werger-bin}}
=== Çavkanî ===
{{çavkanî}}
ks1vdbj5k9iue3bp1ryk6q2nhj9pziy
ciwîyayene
0
299327
6241901
4741495
2026-07-12T21:45:19Z
Kurdanparez
14556
6241901
wikitext
text/x-wiki
== {{ziman|zza}} ==
=== Lêker ===
{{lêker|zza}}
# {{guharto|zza|ciwayene}}
=== Çavkanî ===
* Gramera Kirdkî, Roşan Lezgîn
bcgev5a02stesqzgm8gmn4mrx21w935
alî kirin
0
323788
6241807
6014129
2026-07-12T13:58:59Z
~2026-39288-16
15131
/* Lêker */
6241807
wikitext
text/x-wiki
{{bnr-n|alîkirin}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker ===
{{ku-tewîn-lk|alî kirin|form=gerguhêz|niha=k|borî=kir|pêşgir=alî|valahî=erê}}
{{lêker|ku|c=h-gh}}
# Ji bo kesekî [[bi ser ketin|bi ser bikeve]] yan ji [[tengasî]]yekê rizgar bibe ji kesekî re tiştekî [[dan]] an [[kirin]].
#: {{mînak?|ku}}
==== Herweha ====
[[talî kirin]]
==== Hevmane ====
* {{g|ku|dest dan}}
==== Jê ====
{{kol3|ku|cure=Jê
| [[alîkar]]<q:navdêr>
| [[alîkarî]]<q:navdêr>
}}
==== Bi alfabeyên din ====
* {{ku-ar|ئالی کرن}}
==== Etîmolojî ====
Ji {{heve|ku|alî|kirin}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|stützen}}
* {{Z|fa}}: {{W+|fa|کمک کردن}}, {{W-|fa|مساعدت کردن}}
* {{Z|en}}: {{W+|en|befriend}}, {{W+|en|bestead}}
* {{Z|tr}}: {{W+|tr|desteklemek}}, {{W+|tr|yardım etmek}}, {{W+|tr|yardımda bulunmak}}, {{W+|tr|taraf tutmak}}
{{werger-bin}}
col0psq3n27gp8i7nt8st2qmkqyo4tw
6241808
6241807
2026-07-12T14:01:27Z
~2026-39288-16
15131
/* Herweha */
6241808
wikitext
text/x-wiki
{{bnr-n|alîkirin}}
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker ===
{{ku-tewîn-lk|alî kirin|form=gerguhêz|niha=k|borî=kir|pêşgir=alî|valahî=erê}}
{{lêker|ku|c=h-gh}}
# Ji bo kesekî [[bi ser ketin|bi ser bikeve]] yan ji [[tengasî]]yekê rizgar bibe ji kesekî re tiştekî [[dan]] an [[kirin]].
#: {{mînak?|ku}}
==== Herweha ====
* [[talî kirin]]
==== Hevmane ====
* {{g|ku|dest dan}}
==== Jê ====
{{kol3|ku|cure=Jê
| [[alîkar]]<q:navdêr>
| [[alîkarî]]<q:navdêr>
}}
==== Bi alfabeyên din ====
* {{ku-ar|ئالی کرن}}
==== Etîmolojî ====
Ji {{heve|ku|alî|kirin}}.
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|stützen}}
* {{Z|fa}}: {{W+|fa|کمک کردن}}, {{W-|fa|مساعدت کردن}}
* {{Z|en}}: {{W+|en|befriend}}, {{W+|en|bestead}}
* {{Z|tr}}: {{W+|tr|desteklemek}}, {{W+|tr|yardım etmek}}, {{W+|tr|yardımda bulunmak}}, {{W+|tr|taraf tutmak}}
{{werger-bin}}
qkch6qikno3iij16sr0bu59pdwn56x5
xweşbext
0
380815
6241858
5038545
2026-07-12T20:05:05Z
Wikihez
7344
6241858
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku|z=m}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W+|tr|şanslı}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê1 pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke xweşbext, di nav destnivîsareke şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike|kovar=The Journal of Mesopotamian Studies|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|nivîskar=Ergin Öpengin|url=https://dergipark.org.tr/tr/download/article-file/450470|cîld=3|hejmar=1|sal=2018|r=45}}
=== Herwiha ===
* [[xoşbext]]
=== Etîmolojî ===
Ji {{pêş|ku|xweş-|bext}}.
8po7npgeuzdpteqtd6vrbac3nvyve0t
6241859
6241858
2026-07-12T20:05:31Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241859
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku|z=m}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W+|tr|şanslı}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê1 pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke '''xweşbext''', di nav destnivîsareke şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike|kovar=The Journal of Mesopotamian Studies|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|nivîskar=Ergin Öpengin|url=https://dergipark.org.tr/tr/download/article-file/450470|cîld=3|hejmar=1|sal=2018|r=45}}
=== Herwiha ===
* [[xoşbext]]
=== Etîmolojî ===
Ji {{pêş|ku|xweş-|bext}}.
qir8zpo7el464zpp1tkah4f2fzmoh3p
6241860
6241859
2026-07-12T20:05:48Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241860
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Navdêr ===
{{navdêr|ku|z=m}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W+|tr|şanslı}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê1 pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke '''xweşbext''', di nav destnivîsareke şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike|kovar=The Journal of Mesopotamian Studies|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|nivîskar=Ergin Öpengin|url=https://dergipark.org.tr/tr/download/article-file/450470|cîld=3|hejmar=1|sal=2018|r=45}}
=== Herwiha ===
* [[xoşbext]]
=== Etîmolojî ===
Ji {{qf|ku|xweş|bext}}.
6xjr7xxjlk47rmpv16en1ujol9l0gnu
6241862
6241860
2026-07-12T20:20:33Z
Wikihez
7344
/* {{ziman|ku}} */
6241862
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{navdêr|ku|z=m}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
==== Werger ====
{{werger-ser}}
* {{Z|tr}}: {{W+|tr|şanslı}}
{{werger-bin}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[bextyar]], [[bextewer]], [[bişans]], [[bitalih]], [[bisiûd]], [[bextfireh]]
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê1 pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke '''xweşbext''', di nav destnivîsareke şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike|kovar=The Journal of Mesopotamian Studies|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|nivîskar=Ergin Öpengin|url=https://dergipark.org.tr/tr/download/article-file/450470|cîld=3|hejmar=1|sal=2018|r=45}}
=== Herwiha ===
* [[xoşbext]]
=== Etîmolojî ===
Ji {{qf|ku|xweş|bext}}.
csb4lwzsnksq5kwcox1xcljtrsrvita
photocopy
0
425850
6241935
5859408
2026-07-12T23:25:36Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241935
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{navdêr|en}}
# [[istînsax]], [[fotokopî]]
=== Çavkanî ===
{{çavkanî}}
4t6z6or04tacuhy2fpseoz0c8s7hi1w
6241936
6241935
2026-07-12T23:25:46Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241936
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{navdêr|en}}
# [[istînsax]], [[fotokopî]]
kfzygy42x7iyfe1viw80emssv0ut2k3
tener
0
458654
6241790
5314904
2026-07-12T13:29:14Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* Lêker */
6241790
wikitext
text/x-wiki
== {{ziman|an}} ==
=== Lêker ===
{{lêker|an}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
=== Çavkanî ===
{{rûpela wergerê|an|hebûn}}
== {{ziman|ast}} ==
=== Lêker ===
{{lêker|ast}}
# {{g|ku|hebûn}} (xwedî bûn, di dest de bûn)
=== Çavkanî ===
{{rûpela wergerê|ast|hebûn}}
== {{ziman|ia}} ==
=== Lêker ===
{{lêker|ia}}
# {{g|ku|girtin}}, {{g|ku|zeft kirin}}
=== Çavkanî ===
{{rûpela wergerê|ia|girtin}}
== {{ziman|rm}} ==
=== Lêker ===
{{lêker|rm}}
# {{g|ku|girtin}}, {{g|ku|zeft kirin}}
=== Çavkanî ===
{{rûpela wergerê|rm|girtin}}
== {{ziman|es}} ==
=== Bilêvkirin ===
* {{deng|es|LL-Q1321 (spa)-Anonymât (Kvardek du)-tener.wav|Deng|dever=Fransa}}
* {{deng|es|LL-Q1321 (spa)-Guergana-tener.wav|Deng|dever=Meksîk}}
* {{deng|es|LL-Q1321 (spa)-Prahlad balaji-tener.wav|Deng|dever=}}
=== Lêker ===
{{lêker|es}}
# [[hebûn]]
# dêran
rmt5ejej2iizzs1hqu6c1wkg7cqdsxl
ciwayene
0
467781
6241893
4741492
2026-07-12T21:38:54Z
Kurdanparez
14556
6241893
wikitext
text/x-wiki
== {{ziman|zza}} ==
=== Bilêvkirin ===
* {{zza-kîte}}
* {{zza-IPA}}
=== Lêker ===
{{lêker|zza}}
# [[jîn]], [[jiyan]]
====Herwiha====
* {{g|zza|ciwîyayene}}
====Tewandin====
{{zza-tewîn-lk|reh=ciw}}
====Etîmolojî====
Hevreha {{hv|hac|ژیوای}}, {{hv|ku|jiyan}}.
p9yvmvory8iz5i2dxcw38zujkbmhdyt
deqîq
0
469156
6241928
6181908
2026-07-12T22:56:38Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241928
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Rengdêr ===
{{ku-tewîn-rd|deqîq}}
{{rengdêr|ku}}
# [[rast]], [[tekûz]], [[hahanga]], [[tam]]
==== Ji wêjeya klasîk ====
* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Sirrê le'lê lebê canbexş-i nizanî tu bi behs</br>»E'idi n-nezrete ya naziru fe-s-sirru '''deqîq'''«</br>Bi lebê le'lê şekerxende şikêna şekerek}}
==== Etîmolojî ====
{{bêetîmolojî}}
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|rechtzeitig}}, {{W|de|präzis|guman=erê}}
* {{Z|ar}}: {{W|ar|دقيق|guman=erê}}
* {{Z|fa}}: {{W+|fa|دقیق}}
* {{Z|en}}: {{W+|en|exact}}, {{W+|en|accurate|guman=erê}}, {{W|en|refined|guman=erê}}
{{werger-bin}}
{{mijar|ku|Zimannasî}}
17eirksud6ynlux2ck5bwp3sjmzppfy
milhid
0
610893
6241945
6184851
2026-07-13T05:41:25Z
~2026-39487-86
15132
Werger: +almanî : [[Atheist]] (bi alîkarî)
6241945
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Rengdêr ===
{{rengdêr|ku}}
# [[xwedênenas|Xwedênenas]], [[bêbawer]], kesê/a ku dibêjê ku [[Xwedê]] nîne, [[hin]] kes [[hizir]] dikin ku bûn '''milhid''' tiştek [[pozîtîv]]e
==== Etîmolojî ====
Ji {{deyn|ar|ku|ملحد}}
==== Werger ====
{{werger-ser}}
* {{Z|de}}: {{W+|de|Atheist}}
* {{Z|en}}: {{W|en|atheist}}, {{W|en|lad}}
{{werger-bin}}
gmgm3fh30fzc5wtb4ko9dgy6qzcg6rl
e-book
0
653968
6241873
6055219
2026-07-12T21:22:45Z
Wikihez
7344
/* {{ziman|en}} */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:e-book|en.wikt]]
6241873
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Bilêvkirin ===
:{{ku-tîp|î bûk}}
* {{IPA|en|/i: bʊk/}}
* {{deng|en|LL-Q1860 (eng)-Lepticed7-e-book.wav|Deng|dever=Toulouse, Fransa}}
=== Navdêr ===
{{en-navdêr}}
# [[e-pirtûk]], [[e-pertûk]], [[e-kitêb]], [[e-kîtab]] {{îzah|[[kitêb]]a [[dijîtal]], [[kitêb]]a [[elektronîkî]]}}
==== Herwiha ====
* {{herwiha|en|ebook|eBook}}
==== Jê ====
* {{g|en|e-book reader}}
==== Etîmolojî ====
Kurtkirina {{qal|en|electronic book}}: {{qertaf|en|e-<id:dijîtal>|book}}.
dn76rkgxd8slydofu4ylbwgmvlp5zj0
6241885
6241873
2026-07-12T21:32:38Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241885
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Bilêvkirin ===
:{{ku-tîp|î bûk}}
* {{IPA|en|/i: bʊk/}}
* {{deng|en|LL-Q1860 (eng)-Lepticed7-e-book.wav|Deng|dever=Toulouse, Fransa}}
=== Navdêr ===
{{en-navdêr}}
# [[e-pirtûk]], [[e-pertûk]], [[e-kitêb]], [[e-kîtab]] {{îzah|[[kitêb]]a [[dijîtal]], [[kitêb]]a [[elektronîkî]]}}
==== Herwiha ====
* {{herwiha|en|ebook|eBook}}
==== Jê ====
* {{g|en|e-book reader}}
==== Etîmolojî ====
Kurtkirina {{qal|en|electronic book}}: {{qertaf|en|e-<id:dijîtal>|book}}.
{{K|en|kitêb}}
1i1rta30bk1onftw0e4dicdx7cgnwtp
Şablon:kategorîzebike/belge
10
842012
6241911
6241403
2026-07-12T22:12:28Z
Wikihez
7344
6241911
wikitext
text/x-wiki
{{kurterê|Şablon:K}}
== Bikaranîn ==
* <code><nowiki>{{kategorîzebike|koda zimanî|m1|m2|...|m7}}</nowiki></code>
:Di bin rûpela peyvê de şûnda kategoriyên <code><nowiki>[[Kategorî:m1 bi ziman]][[Kategorî:m2 bi ziman]], ...</nowiki></code> tê bikaranîn.
=== Mînak ===
* <code><nowiki>{{kategorîzebike|ku|riwek|balinde|erdnîgarî}}</nowiki></code>
** Pevy dikeve di nav kategoriyên <tt>[[:Kategorî:Riwek bi {{navê zimanî|ku}}]], [[:Kategorî:Balinde bi {{navê zimanî|ku}}]] û [[:Kategorî:Erdnîgarî bi {{navê zimanî|ku}}]]</tt>.
== Binêre ==
* {{ş|etîket}}
* [[:Kategorî:Şablon (mijar)]]
rx3xmup2e6zcb8i9wx5kpdq1qu9npjf
Bikarhêner:Wikihez/common.css
2
874440
6241756
6241745
2026-07-12T12:08:35Z
Wikihez
7344
6241756
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 — sibling to Nimûne ── */
/* The jêder group sits at the same level as Etîket, Herwiha etc. */
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
/* Main quote textarea — full width, 2-line start height */
.wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* Sub-fields for quote tr/t — same indented style as nimûne sub-fields */
.wiktku-dfn-quote-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-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);
}
/* Each jêder citation is its own <li> inside ol.wiktku-dfn-jeder-list, the same
kind of growing list Nimûne uses — this keeps its indentation identical to
Nimûne's (both are plain <ol> elements) and visually separates citations
from one another when there is more than one. */
.wiktku-dfn-jeder-li {
margin-bottom: 0.6em;
padding-bottom: 0.5em;
}
.wiktku-dfn-jeder-li:not(:last-child) {
border-bottom: 1px dashed var(--wikt-palette-lightgrey);
}
/* Source template selector */
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 4px;
display: block;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
/* 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 */
@media (max-width: 720px) {
.wiktku-dfn-jeder-group 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%;
}
}
086bwj9ukkt6ednuluayuiap7qmeuwh
6241763
6241756
2026-07-12T12:40:55Z
Wikihez
7344
6241763
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 — sibling to Nimûne ── */
/* The jêder group sits at the same level as Etîket, Herwiha etc. */
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
/* Main quote textarea — full width, 2-line start height */
.wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* Sub-fields for quote tr/t — same indented style as nimûne sub-fields */
.wiktku-dfn-quote-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-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);
}
/* Each jêder citation is its own <li> inside ol.wiktku-dfn-jeder-list, the same
kind of growing list Nimûne uses — this keeps its indentation identical to
Nimûne's (both are plain <ol> elements) and visually separates citations
from one another when there is more than one. */
.wiktku-dfn-jeder-li {
margin-bottom: 0.6em;
padding-bottom: 0.5em;
}
.wiktku-dfn-jeder-li:not(:last-child) {
border-bottom: 1px dashed var(--wikt-palette-lightgrey);
}
/* Source template selector */
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 4px;
display: block;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
/* 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;
}
/* Freeform "bi destê xwe binivîsim" manual-source textarea */
textarea.wiktku-dfn-quote-src-manual {
width: 100%;
box-sizing: border-box;
height: calc(4 * 1.4em + 8px);
min-height: calc(4 * 1.4em + 8px);
}
/* Mobile */
@media (max-width: 720px) {
.wiktku-dfn-jeder-group 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%;
}
textarea.wiktku-dfn-quote-src-manual {
font-size: 1em;
height: calc(5 * 1.4em + 8px);
min-height: calc(5 * 1.4em + 8px);
}
}
l78fkgtvxryi2bv6qnf1ooibsydtj63
6241804
6241763
2026-07-12T13:56:07Z
Wikihez
7344
6241804
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;
}
/* ── Werger (translation) groups — one per gloss ── */
/* Each gloss gets its own labeled block of translation rows. */
#wiktku-start-trans .wiktku-trans-group {
margin-bottom: 0.8em;
}
#wiktku-start-trans .wiktku-trans-group:last-child {
margin-bottom: 0;
}
/* Caption naming which gloss this group's translations belong to — only
present when there's more than one gloss to disambiguate between. */
#wiktku-start-trans .wiktku-trans-group-label {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 3px;
}
/* Scope the row list styling to inside a group so future nested elements
(e.g. per-row controls) can't leak across gloss boundaries. */
#wiktku-start-trans .wiktku-trans-group ul.wiktku-trans-list {
margin: 0;
padding: 0;
list-style: none;
}
#wiktku-start-trans .wiktku-trans-group li.wiktku-trans-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
#wiktku-start-trans .wiktku-trans-group ul.wiktku-trans-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* Mobile: full-width rows so the language picker and word fields stack
cleanly instead of competing for horizontal space. */
@media (max-width: 720px) {
#wiktku-start-trans .wiktku-trans-group li.wiktku-trans-row {
flex-direction: column;
}
}
/* ── Quote / citation (jêder) block — sibling to Nimûne ── */
/* The jêder group sits at the same level as Etîket, Herwiha etc. */
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
/* Main quote textarea — full width, 2-line start height */
.wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* Sub-fields for quote tr/t — same indented style as nimûne sub-fields */
.wiktku-dfn-quote-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-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: 4px;
display: block;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
/* 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 */
@media (max-width: 720px) {
.wiktku-dfn-jeder-group 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%;
}
}
7a20zogbf492l4x81vghenxy3gzrtx4
6241811
6241804
2026-07-12T14:06:41Z
Wikihez
7344
6241811
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;
}
/* ── Werger (translation) groups — one per gloss ── */
/* Each gloss gets its own labeled block of translation rows. */
#wiktku-start-trans .wiktku-trans-group {
margin-bottom: 0.8em;
}
#wiktku-start-trans .wiktku-trans-group:last-child {
margin-bottom: 0;
}
/* Caption naming which gloss this group's translations belong to — only
present when there's more than one gloss to disambiguate between. */
#wiktku-start-trans .wiktku-trans-group-label {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 3px;
}
/* Scope the row list styling to inside a group so future nested elements
(e.g. per-row controls) can't leak across gloss boundaries. */
#wiktku-start-trans .wiktku-trans-group ul.wiktku-trans-list {
margin: 0;
padding: 0;
list-style: none;
}
#wiktku-start-trans .wiktku-trans-group li.wiktku-trans-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
#wiktku-start-trans .wiktku-trans-group ul.wiktku-trans-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* Mobile: full-width rows so the language picker and word fields stack
cleanly instead of competing for horizontal space. */
@media (max-width: 720px) {
#wiktku-start-trans .wiktku-trans-group li.wiktku-trans-row {
flex-direction: column;
}
}
/* ── Dûnde (loanword) rows ── */
#wiktku-start-dunde ul.wiktku-dunde-list {
margin: 0;
padding: 0;
list-style: none;
}
#wiktku-start-dunde li.wiktku-dunde-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
#wiktku-start-dunde ul.wiktku-dunde-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* Mobile: full-width rows so the language picker and word fields stack
cleanly instead of competing for horizontal space. */
@media (max-width: 720px) {
#wiktku-start-dunde li.wiktku-dunde-row {
flex-direction: column;
}
}
/* ── Quote / citation (jêder) block — sibling to Nimûne ── */
/* The jêder group sits at the same level as Etîket, Herwiha etc. */
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
/* Main quote textarea — full width, 2-line start height */
.wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* Sub-fields for quote tr/t — same indented style as nimûne sub-fields */
.wiktku-dfn-quote-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-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: 4px;
display: block;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
/* 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 */
@media (max-width: 720px) {
.wiktku-dfn-jeder-group 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%;
}
}
g7mhhijfb90p28q0ymris7gfblopuwn
6241814
6241811
2026-07-12T14:23:07Z
Wikihez
7344
6241814
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;
}
/* ── Full-width, 2-line-start textareas: gloss (mane), nimûne example,
jêder quote — same box shape wherever a sense needs one big field ── */
textarea.wiktku-dfn-mane,
textarea.wiktku-dfn-nimune-text,
.wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote {
width: 100%;
box-sizing: border-box;
height: calc(2 * 1.4em + 8px);
min-height: calc(2 * 1.4em + 8px);
}
/* ── Nimûne + jêder-quote sub-fields (transliteration + translation) ──
Both examples get an indented sub-block with the same tr/t pair, so
their wrapper, sizing and tint rules are shared below. ── */
/* Indented wrapper with a left border to show these belong to the example above */
.wiktku-dfn-nimune-sub,
.wiktku-dfn-quote-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;
}
/* Shared box shape for every tr/t sub-textarea, nimûne or jêder alike */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
.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);
}
/* Nimûne's tr/t fields additionally get compact single-line polish
(narrower minimum width, tighter vertical padding, smaller font) */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
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 — same colors for
both nimûne examples and jêder quotes */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-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) + Etymology (etîmolojî) sections ──
Both are a "template-insert dropdown + one big textarea" pair, so their
layout is shared here; each keeps its own subtle color tint below. ── */
.wiktku-pron-wrap,
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-amber-1); /* warm parchment tint — "sound/speech" */
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-indigo-1); /* cool scholarly tint — "history/word origins" */
}
.wiktku-pron-wrap textarea.wiktku-pron-text,
.wiktku-etym-wrap textarea.wiktku-etym-text {
width: 100%;
box-sizing: border-box;
height: calc(3 * 1.4em + 8px);
min-height: calc(3 * 1.4em + 8px);
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
background: var(--wikt-palette-amber-0); /* barely-there warm tint on the textarea itself */
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
background: var(--wikt-palette-indigo-0); /* barely-there cool tint */
}
/* 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;
}
/* ── Generic "language + growing word list" row widget ──
Shared by any section built as one-language-per-row with an expandable
list of word fields (currently Werger's per-gloss groups and Dûnde).
Sections apply these classes alongside their own specific classes, so
this can be reused for future sections without touching CSS again. */
.wiktku-lang-row-list {
margin: 0;
padding: 0;
list-style: none;
}
.wiktku-lang-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
.wiktku-lang-row-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* Mobile: full-width rows so the language picker and word fields stack
cleanly instead of competing for horizontal space. */
@media (max-width: 720px) {
.wiktku-lang-row {
flex-direction: column;
}
}
/* ── Werger (translation) groups — one per gloss ── */
/* Each gloss gets its own labeled block of translation rows. */
#wiktku-start-trans .wiktku-trans-group {
margin-bottom: 0.8em;
}
#wiktku-start-trans .wiktku-trans-group:last-child {
margin-bottom: 0;
}
/* Caption naming which gloss this group's translations belong to — only
present when there's more than one gloss to disambiguate between. */
#wiktku-start-trans .wiktku-trans-group-label {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 3px;
}
/* ── Dûnde (loanword) rows ──
Layout comes entirely from the generic .wiktku-lang-row-* classes above;
nothing dûnde-specific to add. */
/* ── Quote / citation (jêder) block — sibling to Nimûne ──
The main quote textarea and its tr/t sub-fields share sizing, wrapper,
and tint rules with Nimûne's example fields — see the merged block
above ("Full-width, 2-line-start textareas" / "Nimûne + jêder-quote
sub-fields"). Only jêder-specific layout lives here. */
/* The jêder group sits at the same level as Etîket, Herwiha etc. */
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
/* Source template selector */
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 4px;
display: block;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
/* 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 */
@media (max-width: 720px) {
.wiktku-dfn-jeder-group 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%;
}
}
oft0w3xbhb6uraao6brn25061pd8tty
6241817
6241814
2026-07-12T15:35:51Z
Wikihez
7344
6241817
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;
}
/* ── Shared "box-shaped" textarea sizing ──
Every fixed-height, full-width textarea in the wizard — the gloss
(mane), nimûne example + its tr/t sub-fields, and the jêder quote +
its tr/t sub-fields, plus the pron/etym boxes — uses the same height
formula: rows * line-height + vertical padding. Each selector group
below only sets how many rows it wants via --wiktku-ta-rows; the
formula itself lives here once instead of being repeated per section
(and again per mobile breakpoint). Default is 2 rows. */
#wiktku-start-form textarea.wiktku-dfn-mane,
#wiktku-start-form textarea.wiktku-dfn-nimune-text,
#wiktku-start-form .wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t,
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 2;
width: 100%;
box-sizing: border-box;
height: calc(var(--wiktku-ta-rows) * 1.4em + 8px);
min-height: calc(var(--wiktku-ta-rows) * 1.4em + 8px);
}
/* Pron/etym boxes want one more row than the default. */
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 3;
}
/* Indented wrapper with a left border to show the tr/t sub-fields belong
to the example/quote above (shared by nimûne and jêder alike). */
.wiktku-dfn-nimune-sub,
.wiktku-dfn-quote-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;
}
/* Nimûne's tr/t fields additionally get compact single-line polish
(narrower minimum width, tighter vertical padding, smaller font).
Jêder's tr/t fields keep the plain box shape from the shared rule above. */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t {
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 — same colors for
both nimûne examples and jêder quotes */
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr {
background: var(--wikt-palette-cyan); /* pale cyan — transliteration */
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
background: var(--wikt-palette-palegreen); /* pale green — translation */
}
/* ── 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) + Etymology (etîmolojî) sections ──
Both are a "template-insert dropdown + one big textarea" pair, so their
layout is shared here; each keeps its own subtle color tint below.
The textareas' box shape comes from the shared rule above. ── */
.wiktku-pron-wrap,
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-amber-1); /* warm parchment tint — "sound/speech" */
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-indigo-1); /* cool scholarly tint — "history/word origins" */
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
background: var(--wikt-palette-amber-0); /* barely-there warm tint on the textarea itself */
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
background: var(--wikt-palette-indigo-0); /* barely-there cool tint */
}
/* ── 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;
}
/* ── Generic "language + growing word list" row widget ──
Shared by any section built as one-language-per-row with an expandable
list of word fields (currently Werger's per-gloss groups and Dûnde).
Sections apply these classes alongside their own specific classes, so
this can be reused for future sections without touching CSS again. */
.wiktku-lang-row-list {
margin: 0;
padding: 0;
list-style: none;
}
.wiktku-lang-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
.wiktku-lang-row-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* ── Werger (translation) groups — one per gloss ── */
/* Each gloss gets its own labeled block of translation rows. */
#wiktku-start-trans .wiktku-trans-group {
margin-bottom: 0.8em;
}
#wiktku-start-trans .wiktku-trans-group:last-child {
margin-bottom: 0;
}
/* Caption naming which gloss this group's translations belong to — only
present when there's more than one gloss to disambiguate between. */
#wiktku-start-trans .wiktku-trans-group-label {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 3px;
}
/* ── Dûnde (loanword) rows ──
Layout comes entirely from the generic .wiktku-lang-row-* classes above;
nothing dûnde-specific to add. */
/* ── Quote / citation (jêder) block — sibling to Nimûne ──
The main quote textarea and its tr/t sub-fields share sizing, wrapper,
and tint rules with Nimûne's example fields — see the shared "box-shaped
textarea" rule and the wrapper/tint rules above. Only jêder-specific
layout lives here. */
/* The jêder group sits at the same level as Etîket, Herwiha etc. */
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
/* Source template selector */
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 4px;
display: block;
}
/* Dynamic source fields container */
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
/* 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 (<= 720px) — everything in one place instead of one block
per section, so overrides are easy to scan together.
=================================================================== */
@media (max-width: 720px) {
/* Language + word-list rows stack instead of competing for width. */
.wiktku-lang-row {
flex-direction: column;
}
/* Bump every box-shaped textarea to a bigger, easier-to-type size.
Most fields go to 4 rows; the jêder quote family (which starts one
row taller on desktop) goes to 3 to keep the same visual step-up. */
#wiktku-start-form textarea.wiktku-dfn-mane,
#wiktku-start-form textarea.wiktku-dfn-nimune-text,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 4;
font-size: 1em; /* don't shrink text on mobile */
}
#wiktku-start-form .wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
--wiktku-ta-rows: 3;
font-size: 1em;
}
.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);
}
.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 */
}
.wiktku-dfn-quote-src-row label {
min-width: 6em;
}
input.wiktku-dfn-quote-src-input {
width: 100%;
flex: 1 1 100%;
}
}
cnjz0bte0h8ct9dhq4x83tm0qarbnt9
6241819
6241817
2026-07-12T15:37:39Z
Wikihez
7344
6241819
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.
=================================================================== */
#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;
}
#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;
}
ul.wiktku-ac-results li:active {
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);
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;
}
#wiktku-start-form textarea.wiktku-dfn-mane,
#wiktku-start-form textarea.wiktku-dfn-nimune-text,
#wiktku-start-form .wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t,
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 2;
width: 100%;
box-sizing: border-box;
height: calc(var(--wiktku-ta-rows) * 1.4em + 8px);
min-height: calc(var(--wiktku-ta-rows) * 1.4em + 8px);
}
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 3;
}
.wiktku-dfn-nimune-sub,
.wiktku-dfn-quote-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 {
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,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr {
background: var(--wikt-palette-cyan);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
background: var(--wikt-palette-palegreen);
}
/* ── 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;
}
.wiktku-pron-wrap,
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-amber-1);
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-indigo-1);
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
background: var(--wikt-palette-amber-0);
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
background: var(--wikt-palette-indigo-0);
}
/* ── 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);
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;
}
.wiktku-lang-row-list {
margin: 0;
padding: 0;
list-style: none;
}
.wiktku-lang-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
.wiktku-lang-row-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* ── Werger (translation) groups — one per gloss ── */
#wiktku-start-trans .wiktku-trans-group {
margin-bottom: 0.8em;
}
#wiktku-start-trans .wiktku-trans-group:last-child {
margin-bottom: 0;
}
#wiktku-start-trans .wiktku-trans-group-label {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 3px;
}
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 4px;
display: block;
}
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
.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;
}
@media (max-width: 720px) {
.wiktku-lang-row {
flex-direction: column;
}
#wiktku-start-form textarea.wiktku-dfn-mane,
#wiktku-start-form textarea.wiktku-dfn-nimune-text,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 4;
font-size: 1em;
}
#wiktku-start-form .wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
--wiktku-ta-rows: 3;
font-size: 1em;
}
.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);
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
font-size: 1em;
min-height: 2.4em;
}
.wiktku-dfn-quote-src-row label {
min-width: 6em;
}
input.wiktku-dfn-quote-src-input {
width: 100%;
flex: 1 1 100%;
}
}
4pah3ppj3fb9f03ygqr5vdgisi2zx7c
6241851
6241819
2026-07-12T18:47:51Z
Wikihez
7344
6241851
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.
=================================================================== */
.wiktku-start-step {
padding: 1em 0;
border-bottom: 1px solid #e0e0e0;
}
.wiktku-start-step-question {
font-size: 125%;
}
.wiktku-start-step label {
padding-right: 2em;
}
input[type="text"].wiktku-start-step-field {
width: 100%;
}
input[type="text"].wiktku-start-step-field.wiktku-start-narrow {
width: 20em;
}
#wiktku-start-spinner {
float: right;
margin-left: 1em;
}
#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;
}
#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;
}
ul.wiktku-ac-results li:active {
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);
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;
}
#wiktku-start-form textarea.wiktku-dfn-mane,
#wiktku-start-form textarea.wiktku-dfn-nimune-text,
#wiktku-start-form .wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t,
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 2;
width: 100%;
box-sizing: border-box;
height: calc(var(--wiktku-ta-rows) * 1.4em + 8px);
min-height: calc(var(--wiktku-ta-rows) * 1.4em + 8px);
}
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 3;
}
.wiktku-dfn-nimune-sub,
.wiktku-dfn-quote-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 {
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,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr {
background: var(--wikt-palette-cyan);
}
.wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
.wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
background: var(--wikt-palette-palegreen);
}
/* ── 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;
}
.wiktku-pron-wrap,
.wiktku-etym-wrap {
display: flex;
flex-direction: column;
gap: 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
border: 1px solid var(--wikt-palette-lightgrey);
font-size: 0.9em;
width: 100%;
box-sizing: border-box;
padding: 3px 4px;
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-amber-1);
}
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
background: var(--wikt-palette-indigo-1);
}
.wiktku-pron-wrap textarea.wiktku-pron-text {
background: var(--wikt-palette-amber-0);
}
.wiktku-etym-wrap textarea.wiktku-etym-text {
background: var(--wikt-palette-indigo-0);
}
/* ── 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);
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;
}
.wiktku-lang-row-list {
margin: 0;
padding: 0;
list-style: none;
}
.wiktku-lang-row {
display: flex;
align-items: flex-start;
gap: 6px;
margin-bottom: 4px;
flex-wrap: wrap;
}
.wiktku-lang-row-words {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 3px;
}
/* ── Werger (translation) groups — one per gloss ── */
#wiktku-start-trans .wiktku-trans-group {
margin-bottom: 0.8em;
}
#wiktku-start-trans .wiktku-trans-group:last-child {
margin-bottom: 0;
}
#wiktku-start-trans .wiktku-trans-group-label {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 3px;
}
.wiktku-dfn-jeder-group {
margin-top: 4px;
}
.wiktku-dfn-quote-src-sel {
font-size: 0.9em;
margin-top: 4px;
display: block;
}
.wiktku-dfn-quote-src-fields {
display: flex;
flex-direction: column;
gap: 3px;
margin-top: 4px;
}
.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;
}
@media (max-width: 720px) {
.wiktku-lang-row {
flex-direction: column;
}
#wiktku-start-form textarea.wiktku-dfn-mane,
#wiktku-start-form textarea.wiktku-dfn-nimune-text,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-tr,
#wiktku-start-form .wiktku-dfn-nimune-sub textarea.wiktku-dfn-nimune-t,
#wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text,
#wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text {
--wiktku-ta-rows: 4;
font-size: 1em;
}
#wiktku-start-form .wiktku-dfn-jeder-group textarea.wiktku-dfn-nimune-quote,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-tr,
#wiktku-start-form .wiktku-dfn-quote-sub textarea.wiktku-dfn-nimune-quote-t {
--wiktku-ta-rows: 3;
font-size: 1em;
}
.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);
}
.wiktku-pron-wrap select.wiktku-tpl-insert-select,
.wiktku-etym-wrap select.wiktku-tpl-insert-select {
font-size: 1em;
min-height: 2.4em;
}
.wiktku-dfn-quote-src-row label {
min-width: 6em;
}
input.wiktku-dfn-quote-src-input {
width: 100%;
flex: 1 1 100%;
}
}
f876ekd4m9kaivil7pbd18ycg49lw7l
Modul:dara kategoriyan/ferhengokkatbike/dane/ferhengok
828
876257
6241871
6241472
2026-07-12T21:16:42Z
Wikihez
7344
[[Bikarhêner:Balyozxane/etîket-çêke.js|Etîket-çêke]]: +kitêb
6241871
Scribunto
text/plain
local labels = {}
-- bnr. [[Modul:dara kategoriyan/ferhengokkatbike/dane/rêzimanî]]
labels["agir"] = {
display = "[[agir]]",
topical_categories = true,
description = "default",
parents = {"şewat", "çavkaniyên ronahiyê"},
interwiki = {"fire"},
aliases = {"fire"},
}
labels["ajal"] = {
display = "[[ajal]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} li ser heywanên kedîkirî. [[File:Domestic animals livestock.jpg|thumb|ajal]]",
parents = {"heywan"},
interwiki = {"livestock"},
aliases = {"livestock"},
}
labels["aman"] = {
display = "[[aman]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[aman]]an.",
parents = {"amûr", "mitfax", "alavên malê"},
interwiki = {"kitchenware"},
aliases = {"kitchenware"},
}
labels["amûr"] = {
display = "[[amûr]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[amûr]]an.",
parents = {"teknolojî"},
umbrella = true,
interwiki = {"tools"},
aliases = {"tools"},
}
labels["anatomî"] = {
display = "[[anatomî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[anatomî|anatomiyê]].",
parents = {"biyolojî"},
interwiki = {"anatomy"},
aliases = {"anatomy"},
}
labels["antropolojî"] = {
display = "[[antropolojî]]",
topical_categories = true,
description = "default",
parents = {"zoolojî"},
interwiki = {"anthropology"},
aliases = {"mirovnasî", "anthropology"},
}
labels["astrolojî"] = {
display = "[[astrolojî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[astrolojî|astrolojî]].",
parents = {"remldarî"},
interwiki = {"astrology"},
aliases = {"astrology"},
}
labels["avjenî"] = {
display = "[[avjenî]]",
topical_categories = true,
description = "default",
parents = { "spor"},
interwiki = {"swimming"},
aliases = {"swimming"},
}
labels["astronomî"] = {
display = "[[astronomî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[astronomî|astronomiyê]].",
parents = {"zanist"},
interwiki = {"astronomy"},
aliases = {"stêrnasî", "astronomy"},
}
labels["avahî û pêkhate"] = {
display = "[[avahî]] û [[pêkhate]]",
topical_categories = true,
description = "default",
parents = {"mîmarî"},
umbrella = true,
interwiki = {"Buildings and structures"},
aliases = {"Buildings and structures"},
}
labels["avahî"] = {
display = "[[avahî]]",
topical_categories = true,
description = "default",
parents = {"avahî û pêkhate"},
interwiki = {"Buildings"},
aliases = {"bîna", "Buildings"},
}
labels["alavên malê"] = {
display = "[[alav]]ên [[malê]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[alav]]ên [[mal]]ê.",
parents = {"makîne", "mal"},
interwiki = {"home appliances"},
aliases = {"home appliances"},
}
labels["atmosfer"] = {
display = "[[atmosfer]]",
topical_categories = true,
description = "default",
parents = {"xweza"},
interwiki = {"Atmosphere"},
aliases = {"Atmosphere"},
}
labels["alavên muzîkê"] = {
display = "[[muzîk|alava muzîkê]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[alav]]ên [[muzîk]]ê.",
parents = {"amûr", "muzîk"},
interwiki = {"Musical instruments"},
aliases = {"amûrên muzîkê", "amûra muzîkê", "alava muzîkê", "Musical instruments"},
}
labels["astronotîk"] = {
display = "[[astronotîk]]",
topical_categories = true,
description = "default",
parents = {"zanistên sepandî"},
interwiki = {"Astronautics"},
aliases = {"Astronautics"},
}
labels["ba"] = {
display = "[[ba]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[ba]]yê.",
parents = {"hewa"},
interwiki = {"wind"},
aliases = {"wind"},
}
labels["berhemên behrê"] = {
display = "berhemên behrê",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[berhem]]ên [[behr]]ê.",
parents = {"xwarin"},
interwiki = {"seafood"},
aliases = {"seafood"},
}
labels["bajar"] = {
display = "[[bajar]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[bajar]]an.",
parents = {"erdnîgarî", "serenav"},
interwiki = {"cities"},
aliases = {"cities"},
}
labels["basketbol"] = {
display = "[[basketbol]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[basketbol]]ê.",
parents = {"spor"},
interwiki = {"basketball"},
aliases = {"basketball"},
}
labels["bijîşkî"] = {
display = "[[bijîşkî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[bijîşkî|bijîşkiyê]].",
parents = {"zanist"},
interwiki = {"medicine"},
aliases = {"tib", "tibb", "medicine"},
}
labels["biyolojî"] = {
display = "[[biyolojî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[biyolojî|biyolojiyê]].",
umbrella = true,
parents = {"zanist"},
interwiki = {"biology"},
aliases = {"biology"},
}
labels["boks"] = {
display = "[[boks]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên têkildarî [[boks|boksê]].",
parents = {"spor"},
interwiki = {"boxing"},
aliases = {"boxing"},
}
labels["buxik"] = {
display = "[[mêşûmor]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} li ser [[candar]]ên biçûk yên mîna [[mêş]]an yan jê mezintir in lê [[firîn|nafirin]]. [[Wêne:Insekter.jpg|thumb|Hin buxik]]",
parents = {"heywan"},
interwiki = {"insects"},
aliases = {"insects"},
}
labels["behr"] = {
display = "[[behr]]",
topical_categories = true,
description = "default",
parents = {"erdnîgarî"},
interwiki = {"seas"},
aliases = {"derya", "seas"},
}
labels["berf"] = {
display = "[[berf]]",
topical_categories = true,
description = "default",
parents = {"hewa"},
interwiki = {"snow"},
aliases = {"snow"},
}
labels["bazarkarî"] = {
display = "[[bazarkarî]]",
topical_categories = true,
description = "default",
parents = {"karsazî"},
interwiki = {"marketing"},
aliases = {"bazarkerî", "bazarvanî", "marketing"},
}
labels["bac"] = {
display = "[[bac]]",
topical_categories = true,
description = "default",
parents = {"hikûmet", "hiqûq", "pere"},
interwiki = {"taxation"},
aliases = {"backirin", "taxation"},
}
labels["cihûtî"] = {
display = "[[Cihûtî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên dînê [[cihûtî|cihûtiyê]].",
parents = {"dîn"},
interwiki = {"judaism"},
aliases = {"Cihûtî", "judaism"},
}
labels["cilûberg"] = {
display = "[[cilûberg]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[cilûberg]]an.",
parents = {"mirov"},
interwiki = {"clothing"},
aliases = {"clothing"},
}
labels["civak"] = {
display = "[[civak]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"society"},
aliases = {"society"},
}
labels["cih"] = {
display = "[[cih]]",
topical_categories = true,
description = "default",
parents = {"nav"},
interwiki = {"places"},
aliases = {"places"},
}
labels["çavkaniyên ronahiyê"] = {
display = "[[çavkanî|çavkaniyên]] [[ronahî|ronahiyê]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"ronahî"},
interwiki = {"Light sources"},
aliases = {"Light sources"},
}
labels["çandinî"] = {
display = "[[çandinî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[çandinî|çandiniyê]]",
parents = {"lîsteya ferhengan", "kultur"},
interwiki = {"agriculture"},
aliases = {"cotyarî", "agriculture"},
}
labels["çek"] = {
display = "[[çek]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[çek]]an.",
parents = {"leşkerî"},
interwiki = {"weapons"},
aliases = {"weapons"},
}
labels["çiya"] = {
display = "[[çiya]]",
topical_categories = true,
description = "Navên [[çiya]]yan bi zimanê {{{langname}}.",
parents = {"erdnîgarî"},
interwiki = {"mountains"},
aliases = {"mountains"},
}
labels["Çîn"] = {
display = "[[Çîn]]",
topical_categories = true,
description = "default",
parents = {"dewletên Asyayê", "dewlet"},
interwiki = {"China"},
aliases = {"China"},
}
labels["dinya"] = {
display = "[[dinya]]",
topical_categories = true,
description = "default",
parents = {"xweza"},
interwiki = {"Earth"},
aliases = {"erd", "cîhan", "Earth"},
}
labels["devkî"] = {
display = "[[devkî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} yên ji zimanê standard cuda ne.",
parents = {"zimannasî"},
}
labels["devokî"] = {
display = "[[devokî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} yên [[devokî]] ne.",
parents = {"zimannasî"},
}
labels["dewletên Ewropayê"] = {
display = "[[dewlet]]a [[Ewropa]]yê",
topical_categories = true,
description = "default",
parents = {{name = "dewlet", sort = "Ewropa"}},
interwiki = {"countries in Europe"},
aliases = {"dûgelên Ewropayê", "dûgela Ewropayê", "welata Ewropayê", "welatên Ewropayê", "dewleta Ewropayê", "countries in Europe"},
}
labels["dewletên Asyayê"] = {
display = "[[dewlet]]a [[Asya]]yê",
topical_categories = true,
description = "default",
parents = {{name = "dewlet", sort = "Asya"}},
interwiki = {"countries in Asia"},
aliases = {"dûgelên Asyayê", "dûgela Asyayê", "welata Asyayê", "welatên Asyayê", "dewleta Asyayê", "countries in Asia"},
}
labels["dewletên Afrîkayê"] = {
display = "[[dewlet]]a [[Afrîka]]yê",
topical_categories = true,
description = "default",
parents = {{name = "dewlet", sort = "Afrîka"}},
interwiki = {"countries in Africa"},
aliases = {"dûgelên Afrîkayê", "dûgela Afrîkayê", "welata Afrîkayê", "welatên Afrîkayê", "dewleta Afrîkayê", "countries in Africa"},
}
labels["dar"] = {
display = "[[dar]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[dar]]an.",
parents = {"riwek"},
interwiki = {"trees"},
aliases = {"trees"},
}
labels["dîn"] = {
display = "[[dîn]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[dîn]]î.",
umbrella = true,
parents = {"kultur"},
interwiki = {"religion"},
aliases = {"ol", "olî", "bawerî", "religion"},
}
labels["dîrok"] = {
display = "[[dîrok]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[dîrok]]ê.",
parents = {"zanist"},
interwiki = {"history"},
aliases = {"tarîx", "history"},
}
labels["dewlet"] = {
display = "[[dewlet]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[dewlet]]ên dinyayê.",
parents = {"erdnîgarî", "serenav"},
umbrella = true,
interwiki = {"countries"},
aliases = {"dûgel", "welat", "countries"},
}
labels["dehsal"] = {
display = "[[dehsal]]",
topical_categories = true,
description = "default",
parents = {"termên teqwîmê"},
interwiki = {"Decades"},
aliases = {"Decades"},
}
labels["dewletên Amerîkaya Başûr"] = {
display = "[[dewlet]]a [[Amerîkaya Başûr]]",
topical_categories = true,
description = "default",
parents = {"dewlet"},
interwiki = {"Countries in South America"},
aliases = {"Countries in South America"},
}
labels["deryagerî"] = {
display = "[[deryagerî]]",
topical_categories = true,
description = "default",
parents = {"neqliyat"},
interwiki = {"Nautical"},
aliases = {"Nautical"},
}
labels["demsal"] = {
display = "[[demsal]]",
topical_categories = true,
description = "default",
parents = {"zeman"},
interwiki = {"Seasons"},
aliases = {"Seasons"},
}
labels["enerjî"] = {
display = "[[enerjî]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"xweza", "fizîk"},
interwiki = {"energy"},
aliases = {"wize", "energy"},
}
labels["ekonomî"] = {
display = "[[ekonomî]]",
topical_categories = true,
description = "default",
parents = {"zanist"},
interwiki = {"economics"},
aliases = {"fînans", "aborî", "economics"},
}
labels["evîn"] = {
display = "[[evîn]]",
topical_categories = true,
description = "default",
parents = {"hest"},
interwiki = {"love"},
aliases = {"love"},
}
labels["element"] = {
display = "[[element]]",
topical_categories = true,
description = "Navên [[element]]an bi zimanê {{{langname}}.",
parents = {"kîmya"},
interwiki = {"chemical elements"},
aliases = {"chemical elements"},
}
labels["erdnîgarî"] = {
display = "[[erdnîgarî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[erdnîgarî|erdnîgariyê]].",
umbrella = true,
parents = {"zanist"},
interwiki = {"geography"},
aliases = {"cografya", "geography"},
}
labels["emir"] = {
display = "[[emir]]",
topical_categories = true,
description = "default",
parents = {"leş"},
umbrella = true,
interwiki = {"age"},
aliases = {"age"},
}
labels["elektrîk"] = {
display = "[[elektrîk]]",
topical_categories = true,
description = "default",
parents = {"fizîk"},
interwiki = {"electricity"},
aliases = {"kareba", "kehreba", "electricity"},
}
labels["edebiyat"] = {
display = "[[edebiyat]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[edebiyat|edebiyatê]].",
umbrella = true,
parents = {"kultur"},
interwiki = {"literature"},
aliases = {"wêje", "literature"},
}
labels["formên kevnbûyî"] = {
display = "[[formên kevnbûyî]]",
topical_categories = true,
description = "Formên kevnbûyî yên kelîmeyên {{{langname}}.",
parents = {"zimannasî"},
}
labels["fêkî"] = {
display = "[[fêkî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[fêkî|fêkiyan]].",
parents = {"riwek"},
interwiki = {"fruits"},
aliases = {"fruits"},
}
labels["felsefe"] = {
display = "[[felsefe]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[felsefe|felsefeyê]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"philosophy"},
aliases = {"philosophy"},
}
labels["femînîzm"] = {
display = "[[femînîzm]]",
topical_categories = true,
description = "default",
parents = {"siyaset"},
interwiki = {"feminism"},
aliases = {"feminism"},
}
labels["fizîk"] = {
display = "[[fizîk]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[fizîk|fizîkê]].",
umbrella = true,
parents = {"zanist"},
interwiki = {"physics"},
aliases = {"fîzîk", "physics"},
}
labels["futbol"] = {
display = "[[futbol]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[futbol|futbolê]].",
parents = {"spor"},
interwiki = {"football"},
aliases = {"football"},
}
labels["fîzyolojî"] = {
display = "[[fîzyolojî]]",
topical_categories = true,
description = "default",
parents = {"biyolojî"},
interwiki = {"Physiology"},
aliases = {"fizyolojî", "Physiology"},
}
labels["fîlm"] = {
display = "[[fîlm]]",
topical_categories = true,
description = "default",
parents = {"huner"},
interwiki = {"Film"},
aliases = {"film", "sînema", "Film"},
}
labels["folklor"] = {
display = "[[folklor]]",
topical_categories = true,
description = "default",
parents = {"kultur"},
interwiki = {"folklore"},
aliases = {"folklore", "zargotin"},
}
labels["guhandar"] = {
display = "[[guhandar]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} li ser [[candar]]ên guhanên wan hene. [[Wêne:Goat kid feeding on mothers milk.jpg|thumb|Hin heywanên guhandar]]",
parents = {"heywan"},
interwiki = {"mammals"},
aliases = {"mammals"},
}
labels["gund"] = {
display = "[[gund]]",
topical_categories = true,
description = "Navên [[gund]]an bi zimanê {{{langname}}.",
parents = {"erdnîgarî", "serenav"},
interwiki = {"villages"},
aliases = {"villages"},
}
labels["hest"] = {
display = "[[hest]]",
topical_categories = true,
description = "default",
parents = {"hiş"},
interwiki = {"emotions"},
aliases = {"emotions"},
}
labels["hiş"] = {
display = "[[hiş]]",
topical_categories = true,
description = "default",
parents = {"leş"},
interwiki = {"mind"},
aliases = {"mind"},
}
labels["hemû mijar"] = {
description = "Hemû mijarên zimanê {{{langname}}.",
parents = {{name = "lîsteya ferhengan", sort = " "}},
umbrella = true,
interwiki = {"list of topics"},
aliases = {"list of topics"},
}
labels["herêm"] = {
display = "[[herêm]]",
topical_categories = true,
description = "Navên [[herêm]]an bi zimanê {{{langname}}.",
parents = {"erdnîgarî"},
}
labels["hevdeng"] = {
description = "Kelîmeyên {{{langname}}} yên wek hev bên gotin.",
parents = {"zimannasî"},
}
labels["hewa"] = {
display = "[[hewa]]",
topical_categories = true,
description = "default",
parents = {"atmosfer"},
umbrella = true,
interwiki = {"weather"},
aliases = {"rewşa hewayê", "weather"},
}
labels["hiqûq"] = {
display = "[[hiqûq]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[hiqûq]]ê.",
parents = {"civak"},
interwiki = {"law"},
aliases = {"qanûn", "qanûnî", "dad", "legal", "yasayî", "dadnasî", "law"},
}
labels["hewavanî"] = {
display = "[[hewavanî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[hewavanî|hewavaniyê]].",
parents = {"zanist"},
interwiki = {"aviation"},
aliases = {"hewagerî", "aviation"},
}
labels["heywan"] = {
display = "[[heywan]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[heywan]]an.",
umbrella = true,
parents = {"jîndar"},
interwiki = {"animals"},
aliases = {"animals"},
}
labels["hinduîzm"] = {
display = "[[Hinduîzm]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên dînê [[Hinduîzm|Hinduîzmê]].",
parents = {"dîn"},
interwiki = {"hinduism"},
aliases = {"Hinduîzm", "hinduism"},
}
labels["huner"] = {
display = "[[huner]]",
topical_categories = true,
description = "default",
parents = {"kultur"},
interwiki = {"art"},
aliases = {"art"},
}
labels["hunera şiîrê"] = {
display = "hunera şiîrê",
topical_categories = true,
description = "default",
interwiki = {"Poetry"},
parents = {"edebiyat"},
aliases = {"şiîr", "şi'r", "helbest", "helbestvanî", "nezm"},
}
labels["hikûmet"] = {
display = "[[hikûmet]]",
topical_categories = true,
description = "default",
parents = {"civak", "siyaset"},
umbrella = true,
interwiki = {"Government"},
aliases = {"hikumet", "Government"},
}
labels["informatîk"] = {
display = "[[enformatîk]]",
topical_categories = true, --informatîk beralî dike enformatîk??
description = "Kelîmeyên {{{langname}}} ji bo terimên [[informatîk|informatîkê]].",
umbrella = true,
parents = {"teknolojî"},
aliases = {"enformatîk"},
}
labels["Israîl"] = {
display = "[[Israîl]]",
topical_categories = true,
description = "default",
parents = {"dewletên Asyayê", "dewlet"},
interwiki = {"Israel"},
aliases = {"Îsraêl", "Israel"},
}
labels["înternet"] = {
display = "[[înternet]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[înternet|înternetê]].",
parents = {"kompûternasî"},
interwiki = {"internet"},
aliases = {"internet"},
}
labels["îslam"] = {
display = "[[Îslam]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên dînê [[Îslam|Îslamê]].",
umbrella = true,
parents = {"dîn"},
interwiki = {"islam"},
aliases = {"Îslam", "islam"},
}
labels["îdeolojî"] = {
display = "[[îdeolojî]]",
topical_categories = true,
description = "default",
parents = {"civak"},
interwiki = {"ideologies"},
aliases = {"ideologies"},
}
labels["jîndar"] = {
display = "[[jîndar]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[jîndar]]an.",
umbrella = true,
parents = {"xweza"},
interwiki = {"lifeforms"},
aliases = {"lifeforms"},
}
labels["jeolojî"] = {
display = "[[jeolojî]]",
topical_categories = true,
description = "default",
parents = {"zanist"},
interwiki = {"geology"},
aliases = {"geology"},
}
labels["japonî"] = {
display = "[[japonî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî zimanê [[japonî]].",
parents = {"ziman"},
interwiki = {"japanese"},
aliases = {"japanese"},
}
labels["kultur"] = {
display = "[[kultur]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ên eleqadarî [[kultur|kultura]] mirovahiyê.",
umbrella = true,
parents = {"civak"},
interwiki = {"culture"},
aliases = {"çande", "çand", "culture"},
}
labels["kar"] = {
display = "[[kar]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[kar|karî]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
}
labels["karsazî"] = {
display = "[[karsazî]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {{name = "ekonomî", sort = " "}},
interwiki = {"business"},
aliases = {"business"},
}
labels["kîmya"] = {
display = "[[kîmya]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[kîmya|kîmyayê]].",
umbrella = true,
parents = {"zanist"},
interwiki = {"chemistry"},
aliases = {"chemistry"},
}
labels["kişik"] = {
display = "[[kişik]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[kişik|kişikê]].",
parents = {"lîstik"},
interwiki = {"chess"},
aliases = {"setrenc", "setranc", "şetrenc", "satranc", "chess"},
}
labels["kompûternasî"] = {
display = "[[kompûternasî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[kompûternasî|kompûternasiyê]].",
parents = {"teknolojî", "zanist"},
interwiki = {"computing"},
aliases = {"komputer", "kompûter", "computing"},
}
labels["kulîlk"] = {
display = "[[kulîlk]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[kulîlk]]an.",
parents = {"riwek"},
interwiki = {"flowers"},
aliases = {"flowers"},
}
labels["kes"] = {
display = "[[kes]]",
topical_categories = true,
description = "default",
parents = {"mirov"},
interwiki = {"people"},
aliases = {"people"},
}
labels["kitêb"] = {
display = "[[kitêb]]",
topical_categories = true,
description = "default",
parents = {"edebiyat"},
interwiki = {"Books"},
aliases = {"pirtûk"},
}
labels["lîsteya ferhengan"] = {
--alltopics
description = "Kelîmeyên {{{langname}}} li gorî mijarên mîna \"Xwarin\" an \"Zanist\".",
parents = {{template = "zimankatbike", sort = "ferhengok"}},
umbrella = true,
inSerkategori = true,
interwiki = {"All topics"},
aliases = {"All topics"},
}
labels["leşkerî"] = {
display = "[[leşkerî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[leşkerî|leşkeriyê]].",
umbrella = true,
parents = {"civak"},
interwiki = {"military"},
aliases = {"military"},
}
labels["lîstik"] = {
display = "[[lîstik]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[lîstik|lîstikan]].",
umbrella = true,
parents = {"lîsteya ferhengan", "kultur"},
interwiki = {"games"},
aliases = {"games"},
}
labels["lîstikên vîdeoyî"] = {
display = "[[lîstik]]ên [[vîdeo]]yî",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[lîstik]]ên [[vîdeo]]yî.",
parents = {{name = "lîstik", sort = "vîdeoyî"}, "informatîk"},
interwiki = {"video games"},
aliases = {"video games"},
}
labels["lîstikên zarokan"] = {
display = "[[lîstik]]a [[zarok]]an",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[lîstik|lîstik]]ên [[zarok]]an.",
parents = {{name = "lîstik", sort = "zarok"}},
interwiki = {"children's games"},
aliases = {"lîstika zarokan", "children's games"},
}
labels["leş"] = {
display = "[[leş]]",
topical_categories = true,
description = "default",
parents = {"lîsteya ferhengan"},
umbrella = true,
interwiki = {"body"},
aliases = {"wicûd", "body"},
}
labels["meteorolojî"] = {
display = "[[meteorolojî]]",
topical_categories = true,
description = "default",
parents = {"zanist", "atmosfer"},
interwiki = {"Meteorology"},
aliases = {"hewanasî", "Meteorology"},
}
labels["metonîm"] = {
display = "[[metonîm]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} yên ku bi eslê xwe ve tê gotin ku tiştek an têgihek ne bi navê xwe, lê bi navê tiştekî ku ji nêz ve bi wî tişt an têgihê re têkildar e.",
parents = {"etîmolojî", "zimannasî"},
}
labels["mitfax"] = {
display = "[[mitfax]]",
topical_categories = true,
description = "default",
parents = {"ode"},
interwiki = {"kitchen"},
aliases = {"kulîn", "metbex", "kitchen"},
}
labels["mal"] = {
display = "[[mal]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"civak"},
interwiki = {"home"},
aliases = {"home"},
}
labels["malbat"] = {
display = "[[malbat]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo endamên [[malbat]]ê.",
parents = {"mirov"},
interwiki = {"family"},
aliases = {"family"},
}
labels["masî"] = {
display = "[[masî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} li ser [[heywan]]ên [[avî]] yên ku [[karîn|nikarin]] li [[ziwayî|ziwayiyan]] bi[[jîn]]. [[Wêne:Gullfiskur.jpg|thumb|Masiyek]]",
parents = {"heywan"},
interwiki = {"fish"},
aliases = {"fish"},
}
labels["matematîk"] = {
display = "[[matematîk]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[matematîk]]ê.",
parents = {"zanist"},
interwiki = {"mathematics"},
aliases = {"geometrî", "bîrkarî", "mathematics"},
}
labels["mehên salê"] = {
display = "[[mehên salê]]",
topical_categories = true,
description = "Navên mehên salê bi zimanê {{{langname}}.",
umbrella = true,
parents = {"zeman"},
interwiki = {"months"},
aliases = {"months"},
}
labels["mekanîk"] = {
display = "[[mekanîk]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mekanîk|mekanîkê]].",
parents = {"fizîk"},
interwiki = {"mechanics"},
aliases = {"mechanics"},
}
labels["mesîhî"] = {
display = "[[Mesîhî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên dînê [[Mesîhî|Mesîhiyê]].",
parents = {"dîn"},
interwiki = {"christianity"},
aliases = {"filetî", "Mesîhî", "Xiristiyanî", "xiristiyanî", "christianity"},
}
labels["meslek"] = {
display = "[[meslek]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[pîşe|pîşeyan]].",
parents = {"kar"},
umbrella = true,
interwiki = {"occupations"},
aliases = {"pîşe", "occupations"},
}
labels["metrolojî"] = {
display = "[[metrolojî]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"zanist"},
interwiki = {"metrology"},
aliases = {"metrology"},
}
labels["mîtolojî"] = {
display = "[[mîtolojî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mîtolojî|mîtolojiyê]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"mythology"},
aliases = {"mythology"},
}
labels["mîtolojiya ermenî"] = {
display = "[[mîtolojî|mîtolojiya]] [[ermenî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mîtolojî|mîtolojiya]] [[ermenî]].",
parents = {{name = "mîtolojî", sort = "ermenî"}},
interwiki = {"Armenian mythology"},
aliases = {"Armenian mythology"},
}
labels["mîtolojiya îranî"] = {
display = "[[mîtolojî|mîtolojiya]] [[îranî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mîtolojî|mîtolojiya]] [[îranî]].",
umbrella = true,
parents = {{name = "mîtolojî", sort = "îranî"}},
interwiki = {"Iranian mythology"},
aliases = {"Iranian mythology"},
}
labels["mîtolojiya kurdî"] = {
display = "[[mîtolojî|mîtolojiya]] [[kurdî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mîtolojî|mîtolojiya]] [[kurdî]].",
parents = {{name = "mîtolojî", sort = "kurdî"}},
}
labels["mîtolojiya misrî"] = {
display = "[[mîtolojî|mîtolojiya]] [[misrî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mîtolojî|mîtolojiya]] [[misrî]].",
parents = {{name = "mîtolojî", sort = "misrî"}},
interwiki = {"Egyptian mythology"},
aliases = {"Egyptian mythology"},
}
labels["mîtolojiya yûnanî"] = {
display = "[[mîtolojî|mîtolojiya]] [[yûnanî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mîtolojî|mîtolojiya]] [[yûnanî]].",
parents = {{name = "mîtolojî", sort = "yûnanî"}},
interwiki = {"Greek mythology"},
aliases = {"Greek mythology"},
}
labels["mobîlya"] = {
display = "[[mobîlya]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[mobîlya|mobîlyayan]].",
parents = {"mal"},
interwiki = {"furniture"},
aliases = {"furniture"},
}
labels["mode"] = {
display = "[[mode]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[mode|modeyê]].",
parents = {"kultur"},
interwiki = {"fashion"},
aliases = {"fashion"},
}
labels["muzîk"] = {
display = "[[muzîk]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[muzîk]]ê.",
parents = {"lîsteya ferhengan"},
interwiki = {"music"},
aliases = {"mûzîk", "music"},
}
labels["mirov"] = {
display = "[[mirov]]",
topical_categories = true,
description = "default",
parents = {"lîsteya ferhengan"},
umbrella = true,
interwiki = {"human"},
aliases = {"însan", "human"},
}
labels["makîne"] = {
display = "[[makîne]]",
topical_categories = true,
description = "default",
parents = {"teknolojî"},
interwiki = {"machines"},
aliases = {"machines"},
}
labels["mîmarî"] = {
display = "[[mîmarî]]",
topical_categories = true,
description = "default",
parents = {"zanistên sepandî"},
umbrella = true,
interwiki = {"architecture"},
aliases = {"avahîsazî", "architecture"},
}
labels["malper"] = {
display = "[[malper]]",
topical_categories = true,
description = "default",
parents = {"world Wide Web"},
interwiki = {"Websites"},
aliases = {"Websites"},
}
labels["mirin"] = {
display = "[[mirin]]",
topical_categories = true,
description = "default",
parents = {"leş"},
interwiki = {"death"},
aliases = {"death"},
}
labels["muzîsyen"] = {
display = "[[muzîsyen]]",
topical_categories = true,
description = "default",
parents = {"meslek"},
interwiki = {"musicians"},
aliases = {"muzîkvan", "mûzîkvan", "mûzîsyen", "musicians"},
}
labels["miliyet"] = {
display = "[[miliyet]]",
topical_categories = true,
description = "default",
parents = {"kes"},
interwiki = {"Nationalities"},
aliases = {"netewe", "gel", "milet", "milliyet"},
}
labels["nimûne"] = {
-- display = "[[devkî]]",
-- topical_categories = {"devkî"},
description = "Kelîmeyên ku mînakeke bi zimanê {{{langname}}} hatiye dayîn.",
parents = {"zimannasî"},
}
labels["nifş"] = {
display = "[[nifş]]",
topical_categories = true,
description = "default",
parents = {"emir"},
interwiki = {"generations"},
aliases = {"jenerasyon", "generations"},
}
labels["nifir"] = {
display = "[[nifir]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} bi maneya [[nifir|nifirê]].",
parents = {"zimannasî"},
}
labels["neolojîzm"] = {
display = "[[neolojîzm]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} yên bi [[neolojîzm]]ê hatine çêkirin.",
parents = {"etîmolojî", "zimannasî"},
}
labels["navçe"] = {
display = "[[navçe]]",
topical_categories = true,
description = "Navên [[navçe]]yan bi zimanê {{{langname}}.",
parents = {"erdnîgarî", "serenav"},
interwiki = {"districts"},
aliases = {"districts"},
}
labels["niqteşanî"] = {
display = "[[niqteşanî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[niqteşanî|niqteşaniyê]].",
parents = {{ name = "ziman", sort = " "}},
interwiki = {"punctuation marks"},
aliases = {"punctuation marks"},
}
labels["navgîn"] = {
display = "[[navgîn]]",
topical_categories = true,
description = "default",
parents = {"makîne"},
interwiki = {"vehicles"},
aliases = {"vehicles"},
}
labels["nav"] = {
display = "[[na]]",
topical_categories = true,
description = "default",
parents = {"lîsteya ferhengan"},
interwiki = {"names"},
aliases = {"names"},
}
labels["nivîsîn"] = {
display = "[[nivîsîn]]",
topical_categories = true,
description = "default",
parents = {"ziman"},
umbrella = true,
interwiki = {"writing"},
aliases = {"writing"},
}
labels["nexweşî"] = {
display = "[[nexweşî]]",
topical_categories = true,
description = "default",
parents = {"bijîşkî"},
interwiki = {"diseases"},
aliases = {"êş", "diseases"},
}
labels["neqliyat"] = {
display = "[[neqliyat]]",
topical_categories = true,
description = "default",
parents = {"lîsteya ferhengan"},
interwiki = {"Transport"},
aliases = {"Transport"},
}
labels["ode"] = {
display = "[[ode]]",
topical_categories = true,
description = "default",
parents = {"avahî û pêkhate"},
interwiki = {"rooms"},
aliases = {"jûr", "rooms"},
}
labels["optîk"] = {
display = "[[optîk]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[optîk|optîkê]].",
parents = {"fizîk"},
interwiki = {"optics"},
aliases = {"optics"},
}
labels["okyanûs"] = {
display = "[[okyanûs]]",
topical_categories = true,
description = "Navên [[okyanûs]]yan bi zimanê {{{langname}}.",
parents = {"erdnîgarî"},
interwiki = {"oceans"},
aliases = {"oceans"},
}
labels["otomotîv"] = {
display = "[[otomotîv]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[otomotîv]]ê.",
parents = {"teknolojî"},
interwiki = {"automotive"},
aliases = {"seyare", "ereba", "automotive"},
}
labels["parzemîn"] = {
display = "[[parzemîn]]",
topical_categories = true,
description = "default",
parents = {"erdnîgarî"},
interwiki = {"continents"},
aliases = {"qita", "continents"},
}
labels["parêzgeh"] = {
display = "[[parêzgeh]]",
topical_categories = true,
description = "Navên parêzgehan bi zimanê {{{langname}}.",
parents = {"erdnîgarî"},
interwiki = {"Provinces"},
aliases = {"Provinces"},
}
labels["perwerde"] = {
display = "[[perwerde]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[perwerde|perwerdeyê]].",
parents = {"civak"},
interwiki = {"Education"},
aliases = {"pedagogî", "pedagojî", "Education"},
}
labels["psîkolojî"] = {
display = "[[psîkolojî]]",
topical_categories = true,
description = "default",
parents = {"zanist"},
interwiki = {"psychology"},
aliases = {"derûnnasî", "psychology"},
}
labels["psîkyatrî"] = {
display = "[[psîkyatrî]]",
topical_categories = true,
description = "default",
parents = {"bijîşkî"},
interwiki = {"psychiatry"},
aliases = {"psychiatry"},
}
labels["por"] = {
display = "[[por]]",
topical_categories = true,
description = "default",
parents = {"leş"},
interwiki = {"hair"},
aliases = {"hair"},
}
labels["programkirin"] = {
display = "[[programkirin]]",
topical_categories = true,
description = "default",
parents = {"kompûternasî"},
interwiki = {"programming"},
aliases = {"programming"},
}
labels["pêxemberên Îslamê"] = {
display = "[[pêxember|Pêxemberên]] [[Îslam]]ê",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên pêxemberên [[Îslam|Îslamê]].",
parents = {"Îslam"},
interwiki = {"islamic prophets"},
aliases = {"Pêxemberên Îslamê", "islamic prophets"},
}
labels["purîzm"] = {
display = "[[Nimînok:Ferhengok#purîzm|purîzm]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} bi armanca [[:w:Purîzma zimanî|purîzma zimanî]] tên bikaranîn.",
parents = {"zimannasî"},
aliases = {"pûrizm", "pûrîzm"},
}
labels["patolojî"] = {
display = "[[patolojî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} yên di [[patolojî|patolojiyê]], lêkolîna nexweşiyan, de tê bikaranîn",
parents = {"bijîşkî"},
interwiki = {"Pathology"},
aliases = {"Pathology"},
}
labels["pere"] = {
display = "[[pere]]",
topical_categories = true,
description = "default",
parents = {"karsazî"},
interwiki = {"Money"},
aliases = {"dirav", "Money"},
}
labels["proseyên kîmyewî"] = {
display = "[[prose]]yên [[kîmyewî]]",
topical_categories = true,
description = "default",
parents = {"xweza", "kîmya"},
interwiki = {"Chemical processes"},
aliases = {"proseya kîmyewî", "pêvajoyên kîmyewî", "Chemical processes"},
}
labels["ronahî"] = {
display = "[[ronahî]]",
topical_categories = true,
description = "default",
parents = {"enerjî"},
interwiki = {"light"},
aliases = {"light"},
}
labels["rêzimanî"] = {
display = "[[rêzimanî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[rêziman|rêzimanê]].",
parents = {"zimannasî"},
aliases = {"gramer", "grammar"},
interwiki = {"grammar"},
}
labels["remldarî"] = {
display = "[[remldarî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[remldarî|remldariyê]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"divination"},
aliases = {"divination"},
}
labels["reng"] = {
display = "[[reng]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[reng|rengan]].",
parents = {"lîsteya ferhengan"},
interwiki = {"Colors"},
aliases = {"Colors"},
}
labels["riwek"] = {
display = "[[gulûgiya]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo navên [[gulûgiya]]yan.",
umbrella = true,
parents = {"riweknasî"},
interwiki = {"plants"},
aliases = {"plants", "nebat", "gulûgiya"},
}
labels["riweknasî"] = {
display = "[[riweknasî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[riweknasî|riweknasiyê]].",
umbrella = true,
parents = {"zanist"},
interwiki = {"Botany"},
aliases = {"botanîk", "Botany"},
}
labels["robar"] = {
display = "[[robar]]",
topical_categories = true,
description = "Navên [[robar]]an bi zimanê {{{langname}}.",
parents = {"erdnîgarî"},
interwiki = {"rivers"},
aliases = {"çem", "rivers"},
}
labels["sosyolojî"] = {
display = "[[sosyolojî]]",
topical_categories = true,
description = "default",
parents = {"zanist"},
interwiki = {"sociology"},
aliases = {"civaknasî", "sociology"},
}
labels["salnameya koçî"] = {
display = "[[salnameya koçî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[salnameya koçî]].",
parents = {"zeman", "îslam"},
interwiki = {"Islamic months"},
aliases = {"Islamic months"},
}
labels["sebze"] = {
display = "[[sebze]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[sebze]]yan.",
parents = {"riwek"},
interwiki = {"Vegetables"},
aliases = {"Vegetables"},
}
labels["siyaset"] = {
display = "[[siyaset]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[siyaset|siyasetê]].",
parents = {"lîsteya ferhengan"},
interwiki = {"politics"},
aliases = {"polîtîka", "politics"},
}
labels["spor"] = {
display = "[[spor]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[spor|sporê]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"sports"},
aliases = {"werziş", "werzîş", "sports"},
}
labels["sal"] = {
display = "[[sal]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[sal]]ê.",
parents = {"zeman"},
interwiki = {"years"},
aliases = {"years"},
}
labels["sûc"] = {
display = "[[sûc]]",
topical_categories = true,
description = "default",
parents = {"civak"},
interwiki = {"crime"},
aliases = {"tawan", "crime"},
}
labels["sîstemên nivîsînê"] = {
display = "[[sîstem]]ên [[nivîsîn]]ê",
topical_categories = true,
description = "default",
parents = {"nivîsîn"},
interwiki = {"writing systems"},
aliases = {"writing systems"},
}
labels["şahname"] = {
display = "[[Şahname]]",
topical_categories = true,
description = "Karakter û terimên destana [[Şahname|Şahnameyê]] ya [[:w:Firdewsî|Firdewsî]] bi zimanê {{{langname}}}.",
parents = {"mîtolojiya îranî", "edebiyat", "hunera şiîrê"},
interwiki = {"shahnameh"},
aliases = {"Şahname", "shahnameh"},
}
labels["şîranî"] = {
display = "[[şîranî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[şîranî|şîraniyan]].",
parents = {"xwarin"},
interwiki = {"desserts"},
aliases = {"desserts"},
}
labels["şewat"] = {
display = "[[şewat]]",
topical_categories = true,
description = "default",
parents = {"proseyên kîmyewî"},
umbrella = true,
interwiki = {"Combustion"},
aliases = {"Combustion"},
}
labels["şexsiyet"] = {
display = "[[şexsiyet]]",
topical_categories = true,
description = "default",
parents = {"hiş"},
interwiki = {"personality"},
aliases = {"kesayet", "xû", "xûy", "personality"},
}
labels["teyr"] = {
display = "[[teyr]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} li ser [[candar]]ên mîna [[baz]], [[silêmanê dunikil]] hwd. yên ku [[firîn|difirin]], [[hêk]]an dikin û [[per]] û [[bask]]ên wan hene. [[Wêne:Upupa epops 1 Luc Viatour.jpg|thumb|Teyrek]]",
parents = {"heywan"},
interwiki = {"birds"},
aliases = {"balinde", "birds"},
}
labels["teknolojî"] = {
display = "[[teknolojî]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"technology"},
aliases = {"technology"},
}
labels["tenîs"] = {
display = "[[tenîs]]",
topical_categories = true,
description = "default",
parents = {"spor"},
interwiki = {"tennis"},
aliases = {"tennis"},
}
labels["teolojî"] = {
display = "[[teolojî]]",
topical_categories = true,
description = "default",
parents = {"felsefe"},
interwiki = {"theology"},
aliases = {"theology"},
}
labels["tilyak"] = {
display = "[[tilyak]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[cûn]]ên [[tilyak]]an.",
parents = {"lîsteya ferhengan"},
interwiki = {"drugs"},
aliases = {"drugs"},
}
labels["termên teqwîmê"] = {
display = "[[term]]ên [[teqwîm]]ê",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[term]]ên [[teqwîm]]ê.",
parents = {"zeman"},
interwiki = {"calendar terms"},
aliases = {"têgihên teqwîmê", "calendar terms"},
}
labels["toksîkolojî"] = {
display = "[[toksîkolojî]]",
topical_categories = true,
description = "default",
parents = {"bijîşkî"},
interwiki = {"toxicology"},
aliases = {"jehrnasî", "toxicology"},
}
labels["televizyon"] = {
display = "[[televizyon]]",
topical_categories = true,
description = "default",
parents = {"kultur"},
interwiki = {"television"},
aliases = {"television", "televîzyon"},
}
labels["tiyatro"] = {
display = "[[tiyatro]]",
topical_categories = true,
description = "default",
parents = {"huner"},
interwiki = {"Theater"},
aliases = {"şano", "theater"},
}
labels["vexwarin"] = {
display = "[[vexwarin]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[vexwarin|vexwarinan]].",
parents = {"xwarin û vexwarin"},
interwiki = {"beverages"},
aliases = {"beverages"},
}
labels["wênegirî"] = {
display = "[[wênegirî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[wênegirî|wênegiriyê]].",
parents = {"huner"},
interwiki = {"photography"},
aliases = {"wênekêşî", "photography"},
}
labels["world Wide Web"] = {
display = "[[www]]",
topical_categories = true,
description = "default",
parents = {"înternet"},
umbrella = true,
interwiki = {"World Wide Web"},
aliases = {"www", "World Wide Web", "WWW"},
}
labels["xweza"] = {
display = "[[xweza]]",
topical_categories = true,
description = "default",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"nature"},
aliases = {"sirişt", "sirûşt", "nature"},
}
labels["xwarin û vexwarin"] = {
display = "[[xwarin]] û [[vexwarin]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[xwarin]] û [[vexwarin|vexwarinan]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"food and drink"},
aliases = {"food and drink"},
}
labels["xişok"] = {
display = "[[xişok]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} li ser [[candar]]ên ku xwîn sar in, [[hêk]]an dikin, û xwe [[xişandin|dixişînin]] ji bo [[birêveçûn]]ê. [[Wêne:Peninsular Rock Agama (Psammophilus dorsalis) in Hyderabad W IMG 5666.jpg|thumb|Xişokek]]",
parents = {"heywan"},
interwiki = {"reptiles"},
aliases = {"reptiles"},
}
labels["xwarin"] = {
display = "[[xwarin]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo [[xwarin|xwarinan]].",
parents = {"xwarin û vexwarin"},
interwiki = {"foods"},
aliases = {"foods", "food"},
}
labels["xew"] = {
display = "[[xew]]",
topical_categories = true,
description = "default",
parents = {"leş"},
interwiki = {"Sleep"},
aliases = {"razan", "raketin", "sleep"},
}
labels["zanist"] = {
display = "[[zanist]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[zanist|zanistê]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"sciences"},
aliases = {"science", "sciences", "ilm", "îlm"},
}
labels["zeman"] = {
display = "[[zeman]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[zeman|zeman]].",
umbrella = true,
parents = {"lîsteya ferhengan"},
interwiki = {"time"},
aliases = {"wext", "dem", "time"},
}
labels["zerdeştî"] = {
display = "[[Zerdeştî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên dînê [[Zerdeştî|Zerdeştiyê]].",
parents = {"dîn"},
interwiki = {"Zoroastrianism"},
aliases = {"Zerdeştî", "Zoroastrianism"},
}
labels["ziman"] = {
display = "[[ziman]]",
topical_categories = true,
description = "Navên zimanan bi zimanê {{{langname}}.",
parents = {"lîsteya ferhengan"},
interwiki = {"languages"},
aliases = {"language"},
}
labels["zimannasî"] = {
display = "[[zimannasî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} ji bo terimên [[zimannasî|zimannasiyê]].",
umbrella = true,
parents = {"zanist"},
interwiki = {"linguistics"},
aliases = {"zimanzanî", "linguistics"},
}
labels["zoolojî"] = {
display = "[[zoolojî]]",
topical_categories = true,
description = "Kelîmeyên {{{langname}}} têkildarî [[zoolojî|zoolojiyê]].",
umbrella = true,
parents = {"biyolojî", "zanist"},
interwiki = {"zoology"},
aliases = {"ajalnasî", "heywannasî", "zoology"},
}
labels["zanistên sepandî"] = {
display = "[[zanistên sepandî]]",
topical_categories = true,
description = "default",
parents = {"zanist"},
umbrella = true,
interwiki = {"applied sciences"},
aliases = {"zanista sepandî", "applied sciences"},
}
labels["deprecated label"] = {
aliases = {"emergency", "greekmyth", "industry", "morphology", "musici", "quantum", "vector"},
display = "<span style=\"color:red;\"><b>deprecated label</b></span>",
deprecated = true,
}
return require("Module:labels").finalize_data(labels)
67fz4cnj16v9v67wg17ze8a15cgh1y0
Modul:affix/templates
828
935899
6241848
6239494
2026-07-12T18:09:44Z
Wikihez
7344
6241848
Scribunto
text/plain
local export = {}
local m_affix = require("Module:affix")
local m_utilities = require("Module:utilities")
local en_utilities_module = "Module:en-utilities"
local parameter_utilities_module = "Module:parameter utilities"
local pseudo_loan_module = "Module:affix/pseudo-loan"
local function is_property_key(k)
return require(parameter_utilities_module).item_key_is_property(k)
end
local recognized_affix_types = {
prefix = "pêşgir",
pre = "pêşgir",
suffix = "paşgir",
suf = "paşgir",
interfix = "navgir",
inter = "navgir",
infix = "navgir",
["in"] = "navgir",
circumfix = "circumfix",
circum = "circumfix",
["non-affix"] = "non-affix",
naf = "non-affix",
root = "non-affix",
}
local function pre_normalize_affix_type(data)
local modtext = data.modtext
modtext = modtext:match("^<(.*)>$")
if not modtext then
error(("Internal error: Passed-in modifier isn't surrounded by angle brackets: %s"):format(data.modtext))
end
if recognized_affix_types[modtext] then
modtext = "type:" .. modtext
end
return "<" .. modtext .. ">"
end
-- Parse raw arguments. A single parameter `data` is passed in, with the following fields:
-- * `raw_args`: The raw arguments to parse, normally taken from `frame:getParent().args`.
-- * `extra_params`: An optional function of one argument that is called on the `params` structure before parsing; its
-- purpose is to specify additional allowed parameters or possibly disable parameters.
-- * `has_source`: There is a source-language parameter following 1= (which becomes the "destination" language
-- parameter) and preceding the terms. This is currently used for {{pseudo-loan}}.
-- * `ilang`: If given, it is a language object that serves as the default for the language. If specified, there is no
-- language code specified in 1=; instead the term parameters start directly at 1= (or at 2= if `has_source` is
-- given).
-- * `require_index_for_pos`: There is no separate |pos= parameter distinct from |pos1=, |pos2=, etc. Instead,
-- specifying |pos= results in an error.
-- * `allow_type`: Allow |type1=, |type2=, etc. or inline <type:...> for the affix type, and allow a separate |type=
-- parameter for the etymology type (FIXME: this may be confusing; consider changing the etymology type to |etype=).
--
-- Note that all language parameters are allowed to be etymology-only languages.
--
-- Return five values ARGS, ITEMS, LANG_OBJ, SCRIPT_OBJ, SOURCE_LANG_OBJ where ARGS is a table of the parsed arguments;
-- ITEMS is the list of parsed items; LANG_OBJ is the language object corresponding to the language code specified in 1=
-- (or taken from `ilang` if given); SCRIPT_OBJ is the script object corresponding to sc= (if given, otherwise nil); and
-- SOURCE_LANG_OBJ is the language object corresponding to the source-language code specified in 2= (or 1= if `ilang` is
-- given) if `has_source` is specified (otherwise nil).
local function parse_args(data)
local raw_args = data.raw_args
local has_source = data.has_source
local ilang = data.ilang
if raw_args.lang then
error("The |lang= parameter is not used by this template. Place the language code in parameter 1 instead.")
end
local term_index = (ilang and 1 or 2) + (has_source and 1 or 0)
local params = {
[term_index] = {list = true, allow_holes = true},
["sort"] = {},
["ziman"] = {alias_of = "lang", list = true, allow_holes = true, require_index = true},
["nocap"] = {type = "boolean"}, -- always allow this even if not used, for use with {{surf}}, which adds it
["hûr"] = {alias_of = "nocap", type = "boolean"}, -- always allow this even if not used, for use with {{surf}}, which adds it
["w"] = {alias_of = "t", list = true, allow_holes = true,},
["cuda"] = {alias_of = "alt", list = true, allow_holes = true,},
}
if not ilang then
params[1] = {required = true, type = "language", default = "und"}
end
local source_index
if has_source then
source_index = term_index - 1
params[source_index] = {required = true, type = "language", default = "und"}
end
local m_param_utils = require(parameter_utilities_module)
local param_mod_source = {
-- We want to require an index for all params (or use separate_no_index, which also requires an index for the
-- param corresponding to the first item).
{default = true, require_index = true},
{group = {"link", "ref", "lang", "q", "l"}},
-- Override these two to have separate_no_index, unless `data.require_index_for_pos` is specified.
{param = "lit", separate_no_index = true},
{param = "pos", separate_no_index = not data.require_index_for_pos, require_index = data.require_index_for_pos},
{param = "w", alias_of = "t"},
{param = "tercime", alias_of = "t"},
{param = "wate", alias_of = "t"},
{param = "cuda", alias_of = "alt"},
{param = "c", alias_of = "g"},
{param = "z", alias_of = "g"},
{param = "e", alias_of = "l"},
{param = "crz", alias_of = "pos"},
{param = "hrf", alias_of = "lit"},
}
if data.allow_type then
table.insert(param_mod_source, {param = "type", separate_no_index = true})
end
local param_mods = m_param_utils.construct_param_mods(param_mod_source)
if data.extra_params then
data.extra_params(params)
end
local items, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params {
params = params,
param_mods = param_mods,
raw_args = raw_args,
termarg = term_index,
parse_lang_prefix = true,
track_module = "homophones",
disallow_custom_separators = true,
-- For compatibility, we need to not skip completely unspecified items. It is common, for example, to do
-- {{suffix|lang||foo}} to generate "+ -foo".
dont_skip_items = true,
-- Allow e.g. <infix> to be specified in place of <type:infix>.
pre_normalize_modifiers = pre_normalize_affix_type,
-- Don't pass in `lang` or `sc`, as they will be used as defaults to initialize the items, which we don't want
-- (particularly for `lang`), as the code in [[Module:affix]] uses the presence of `lang` as an indicator that
-- a part-specific language was explicitly given.
}
local lang = ilang or args[1]
local source
if has_source then
source = args[source_index]
end
-- For compatibility with the prior code, we need to convert items without term or properties to nil.
for i = 1, #items do
local item = items[i]
local saw_item_property = item.term
if not saw_item_property then
for k, v in pairs(item) do
if is_property_key(k) then
saw_item_property = true
break
end
end
end
if not saw_item_property then
items[i] = nil
elseif item.type then
-- Validate and canonicalize affix types.
if not recognized_affix_types[item.type] then
local valid_types = {}
for k in pairs(recognized_affix_types) do
insert(valid_types, ("'%s'"):format(k))
end
table.sort(recognized_affix_types)
error(("Unrecognized affix type '%s' in item %s; valid values are %s"):format(
item.type, item.itemno, table.concat(valid_types, ", ")))
else
item.type = recognized_affix_types[item.type]
end
end
end
if args.type and args.type.default and not m_affix.etymology_types[args.type.default] then
error("Unrecognized etymology type: '" .. args.type.default .. "'")
end
return args, items, lang, args.sc.default, source
end
local function augment_affix_data(data, args, lang, sc)
data.lang = lang
data.sc = sc
data.pos = args.pos and args.pos.default
data.lit = args.lit and args.lit.default
data.sort_key = args.sort
data.type = args.type and args.type.default
data.nocap = args.nocap
data.notext = args.notext
data.nocat = args.nocat
data.force_cat = args.force_cat
data.l = args.l.default
data.ll = args.ll.default
data.q = args.q.default
data.qq = args.qq.default
return data
end
function export.affix(frame)
local function extra_params(params)
params.notext = {type = "boolean"}
params["nivîs"] = {alias_of = "notext", type = "boolean"}
params["nivîsna"] = {alias_of = "notext", type = "boolean"}
params.nocat = {type = "boolean"}
params["nekat"] = {alias_of = "nocat", type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
allow_type = true,
}
-- There must be at least one part to display. If there are gaps, a term
-- request will be shown.
if not next(parts) and not args.type.default then
if mw.title.getCurrentTitle().nsText == "Şablon" then
parts = { {term = "pêşgir-"}, {term = "reh"}, {term = "-paşgir"} }
else
error("You must provide at least one part.")
end
end
return m_affix.show_affix(augment_affix_data({ parts = parts }, args, lang, sc))
end
function export.compound(frame)
local function extra_params(params)
params.notext = {type = "boolean"}
params["nivîs"] = {alias_of = "notext", type = "boolean"}
params.nocat = {type = "boolean"}
params["nekat"] = {alias_of = "nocat", type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
allow_type = true,
}
-- There must be at least one part to display. If there are gaps, a term
-- request will be shown.
if not next(parts) and not args.type.default then
if mw.title.getCurrentTitle().nsText == "Şablon" then
parts = { {term = "ewil"}, {term = "paşîn"} }
else
error("You must provide at least one part of a compound.")
end
end
return m_affix.show_compound(augment_affix_data({ parts = parts }, args, lang, sc))
end
function export.compound_like(frame)
local iparams = {
["lang"] = {type = "language"},
["template"] = {},
["text"] = {},
["oftext"] = {},
["cat"] = {},
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local function extra_params(params)
params.notext = {type = "boolean"}
params.nocat = {type = "boolean"}
params.force_cat = {type = "boolean"}
params.nekat = {alias_of = "nocat"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
ilang = iargs.lang,
-- FIXME, why are we doing this? Formerly we had 'params.pos = nil' whose intention was to disable the overall
-- pos= while preserving posN=, which is equivalent to the following using the new syntax. But why is this
-- necessary?
require_index_for_pos = true,
}
local template = iargs.template
local nocat = args.nocat
local notext = args.notext
local text = not notext and iargs.text
local oftext = not notext and (iargs.oftext or text and "of")
local cat = not nocat and iargs.cat
if not next(parts) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
parts = { {term = "ya ewil"}, {term = "ya diduyan"} }
end
end
return m_affix.show_compound_like(augment_affix_data({ parts = parts, text = text, oftext = oftext, cat = cat },
args, lang, sc))
end
function export.surface_analysis(frame)
local function ine(arg)
-- Since we're operating before calling [[Module:parameters]], we need to imitate how that module processes
-- arguments, including trimming since numbered arguments don't have automatic whitespace trimming.
if not arg then
return arg
end
arg = mw.text.trim(arg)
if arg == "" then
arg = nil
end
return arg
end
local parent_args = frame:getParent().args
local etymtext
local arg1 = ine(parent_args[1])
if not arg1 then
-- Allow omitted first argument to just display "By surface analysis".
etymtext = ""
elseif arg1:find("^%+") then
-- If the first argument (normally a language code) is prefixed with a +, it's a template name.
local template_name = arg1:sub(2)
local new_args = {}
for i, v in pairs(parent_args) do
if type(i) == "number" then
if i > 1 then
new_args[i - 1] = v
end
else
new_args[i] = v
end
end
new_args.nocap = true
etymtext = ", " .. frame:expandTemplate { title = template_name, args = new_args }
end
if etymtext then
return (ine(parent_args.nocap) and "b" or "B") .. "i [[Nimînok:Ferhengok#analîza şiklî|analîza şiklî]]" ..
etymtext
end
local function extra_params(params)
params.notext = {type = "boolean"}
params.nocat = {type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = parent_args,
extra_params = extra_params,
allow_type = true,
}
-- There must be at least one part to display. If there are gaps, a term
-- request will be shown.
if not next(parts) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
parts = { {term = "first"}, {term = "second"} }
else
error("You must provide at least one part.")
end
end
return m_affix.show_surface_analysis(augment_affix_data({ parts = parts }, args, lang, sc))
end
local function check_max_items(items, max_allowed)
if #items > max_allowed then
local bad_item = items[max_allowed + 1]
if bad_item.term then
error(("At most %s terms can be specified but saw a term specified for term #%s")
:format(max_allowed, max_allowed + 1))
else
for k, v in pairs(bad_item) do
if is_property_key(k) then
error(("At most %s terms can be specified but saw a value for property '%s' of term #%s")
:format(max_allowed, k, max_allowed + 1))
end
end
end
error(("Internal error: Something wrong, %s items generated when there should be at most %s, but item #%s doesn't have a term or any properties")
:format(#items, max_allowed, max_allowed + 1))
end
end
function export.circumfix(frame)
local function extra_params(params)
params.nocat = {type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
check_max_items(parts, 3)
local prefix = parts[1]
local base = parts[2]
local suffix = parts[3]
-- Just to make sure someone didn't use the template in a silly way
if not (prefix and base and suffix) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
prefix = {term = "navgir", alt = "pêşgir"}
base = {term = "kok"}
suffix = {term = "navgir", alt = "paşgir"}
else
error("You must specify a prefix part, a base term and a suffix part.")
end
end
return m_affix.show_circumfix(augment_affix_data({ prefix = prefix, base = base, suffix = suffix }, args, lang, sc))
end
function export.confix(frame)
local function extra_params(params)
params.nocat = {type = "boolean"}
params["nekat"] = {alias_of = "nocat", type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
check_max_items(parts, 3)
local prefix = parts[1]
local base = parts[3] and parts[2] or nil
local suffix = parts[3] or parts[2]
-- Just to make sure someone didn't use the template in a silly way
if not (prefix and suffix) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
prefix = {term = "pêşgir"}
suffix = {term = "paşgir"}
else
error("You must specify a prefix part, an optional base term and a suffix part.")
end
end
return m_affix.show_confix(augment_affix_data({ prefix = prefix, base = base, suffix = suffix }, args, lang, sc))
end
function export.pseudo_loan(frame)
local function extra_params(params)
params.notext = {type = "boolean"}
params.nocat = {type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc, source = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
has_source = true,
-- FIXME, why are we doing this? Formerly we had 'params.pos = nil' whose intention was to disable the overall
-- pos= while preserving posN=, which is equivalent to the following using the new syntax. But why is this
-- necessary?
require_index_for_pos = true,
}
return require(pseudo_loan_module).show_pseudo_loan(
augment_affix_data({ source = source, parts = parts }, args, lang, sc))
end
function export.infix(frame)
local function extra_params(params)
params.nocat = {type = "boolean"}
params["nekat"] = {alias_of = "nocat", type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
check_max_items(parts, 3)
local base = parts[1]
local infix = parts[2]
-- Just to make sure someone didn't use the template in a silly way
if not (base and infix) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
base = {term = "kok"}
infix = {term = "navgir"}
else
error("You must provide a base term and an infix.")
end
end
return m_affix.show_infix(augment_affix_data({ base = base, infix = infix }, args, lang, sc))
end
function export.prefix(frame)
local function extra_params(params)
params.nocat = {type = "boolean"}
params["nekat"] = {alias_of = "nocat", type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
local prefixes = parts
local base = nil
local max_prefix = 0
for k, v in pairs(prefixes) do
max_prefix = math.max(k, max_prefix)
end
if max_prefix >= 2 then
base = prefixes[max_prefix]
prefixes[max_prefix] = nil
end
-- Just to make sure someone didn't use the template in a silly way
if not next(prefixes) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
base = {term = "kok"}
prefixes = { {term = "pêşgir"} }
else
error("You must provide at least one prefix.")
end
end
return m_affix.show_prefix(augment_affix_data({ prefixes = prefixes, base = base }, args, lang, sc))
end
function export.suffix(frame)
local function extra_params(params)
params.nocat = {type = "boolean"}
params["nekat"] = {alias_of = "nocat", type = "boolean"}
params.force_cat = {type = "boolean"}
end
local args, parts, lang, sc = parse_args {
raw_args = frame:getParent().args,
extra_params = extra_params,
}
local base = parts[1]
local suffixes = {}
for k, v in pairs(parts) do
suffixes[k - 1] = v
end
-- Just to make sure someone didn't use the template in a silly way
if not next(suffixes) then
if mw.title.getCurrentTitle().nsText == "Şablon" then
base = {term = "kok"}
suffixes = { {term = "paşgir"} }
else
error("You must provide at least one suffix.")
end
end
return m_affix.show_suffix(augment_affix_data({ base = base, suffixes = suffixes }, args, lang, sc))
end
function export.derivsee(frame)
local iargs = frame.args
local iparams = {
["derivtype"] = {},
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local params = {
["head"] = {},
["ser"] = {alias_of = "head"},
["id"] = {},
["sc"] = {type = "script"},
["pos"] = {},
}
local derivtype = iargs.derivtype
params[1] = {required = "true", type = "language", default = "und"}
params[2] = {}
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = args[1]
local term = args[2] or args.head
local id = args.id
local sc = args.sc
local pos = args.pos or ""
if not term then
local SUBPAGE = mw.title.getCurrentTitle().subpageText
if lang:hasType("reconstructed") or mw.title.getCurrentTitle().nsText == "Jinûvesazî" then
term = "*" .. SUBPAGE
elseif lang:hasType("appendix-constructed") then
term = SUBPAGE
else
term = SUBPAGE
end
end
local category = nil
local langname = lang:getFullName()
if (derivtype == "pêkhatî" and pos == nil) then
category = "Peyvên " .. langname .. " yên pêkhatî bi " .. term
elseif derivtype == "compound" and pos == "verbs" then
category = langname .. " compound " .. pos .. " formed with " .. term
elseif derivtype == "pêkhatî" then
category = "Peyvên " .. langname .. " yên pêkhatî bi " .. term
else
category = "Peyvên " .. langname .. " " .. pos .. "bi " .. derivtype .. "a " .. term .. (id and " (" .. id .. ")" or "")
end
return require('Module:collapsible category tree').make{
lang = lang,
sc = sc,
category = category,
}
end
return export
mym6cnv222mods3u8my3kqsex1ah91r
Şablon:ferhengok
10
958576
6241905
2026-07-12T21:48:44Z
Wikihez
7344
Wikihezî/ê navê [[Şablon:ferhengok]] weke [[Şablon:etîket]] guhart
6241905
wikitext
text/x-wiki
#BERALÎKIRIN [[Şablon:etîket]]
svv5wgmuhew37s4h7h16eert1t1vj2v
6241912
4908053
2026-07-12T22:13:29Z
Wikihez
7344
Wikihezî/ê navê [[Şablon:nimînok]] weke [[Şablon:ferhengok]] guhart
4908053
wikitext
text/x-wiki
{{#invoke:glossary|link}}<!--
--><noinclude>
{{documentation}}
</noinclude>
2gfc2bdgt00us8bb4kn5xfj7lxil6dj
Şablon:ferhengok/belge
10
963901
6241914
4918082
2026-07-12T22:13:29Z
Wikihez
7344
Wikihezî/ê navê [[Şablon:nimînok/belge]] weke [[Şablon:ferhengok/belge]] guhart
4918082
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
== Bikaranîn ==
{{Lua bikartîne|Modul:glossary}}
Ev şablon ji bo lînkkirina [[Nimînok:Ferhengok]] tê bikaranîn.
=== Mînak ===
Heke navê ku li {{ş|lenger}}ê hatiyê danîn û ya peyvê eynî be hingê tenê {{param|1}} tê bikaranîn:
* {{şx|nimînok|cotreh}} → {{nimînok|cotreh}}
* {{şx|nimînok|yekser|wergerandina yekser}} → {{nimînok|yekser|wergerandina yekser}}
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
kgkhlo52xzgsck77226fzrzfpt1kjqj
6241917
6241914
2026-07-12T22:15:19Z
Wikihez
7344
6241917
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
== Bikaranîn ==
{{Lua bikartîne|Modul:glossary}}
Ev şablon ji bo lînkkirina [[Nimînok:Ferhengok]] tê bikaranîn.
=== Nimûne ===
Heke navê ku li {{ş|lenger}}ê hatiyê danîn û ya kelimeye eynî be wê demê tenê {{param|1}} were bikaranîn bes e:
* {{şx|nimînok|cotreh}} → {{nimînok|cotreh}}
* {{şx|nimînok|yekser|wergerandina yekser}} → {{nimînok|yekser|wergerandina yekser}}
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
kizeb0r1ew5gicca2xobhwvkhn14ah8
6241918
6241917
2026-07-12T22:15:45Z
Wikihez
7344
6241918
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
== Bikaranîn ==
{{Lua bikartîne|Modul:glossary}}
Ev şablon ji bo lînkkirina [[Nimînok:Ferhengok]] tê bikaranîn.
=== Nimûne ===
Heke navê ku li {{ş|lenger}}ê hatiyê danîn û ya kelimeye eynî be wê demê tenê {{param|1}} were bikaranîn bes e:
* {{şx|ferhengok|cotreh}} → {{ferhengok|cotreh}}
* {{şx|ferhengok|yekser|wergerandina yekser}} → {{ferhengok|yekser|wergerandina yekser}}
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
ek0dxjr6qqa6cj5anl8y0etkmptu4bf
Bikarhêner:Wikihez/templateScript2.js
2
968069
6241921
6240447
2026-07-12T22:31:04Z
Wikihez
7344
6241921
javascript
text/javascript
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
var title = mw.config.get('wgTitle');
// Remove '=' from the title using the replace method
var modifiedTitle = title.replace(/=/g, '');
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
pathoschild.TemplateScript.add({
name:'kolon',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/{{\)}}/g, '}}')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '|$2<q:$1>')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$3<q:$1>')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$2')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '|$1')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'nimûne',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/#:\s*'{2}(.*?)'{2}\n/g, '#: {{nm|tr|$1|rêz=1}}\n')
.replace(/#:\s*'{2}(.*?)'{2}\s*\(([^\)]+)\)\.?\n/g, '#: {{nm|tr|$1|$2|rêz=1}}\n')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Formata [[Şablon:nimûne|nimûneyan]]+')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'parentez bike îzah',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\(([^\)]+)\)/g, '{{îzah|$1}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'bnr bike ku-Latn',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr(2)?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=-}}\n# {{ku-Latn|$2}}\n\n==== Bi alfabeyên din ====\n* {{ku-ar|' + title + '}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: [[Şablon:ku-Latn|{{ku-Latn}}]]+')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'herwiha',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$2||$1}}')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '| {{hw|ku|$2}}')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$1}}')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'ji dewikt',
// forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{Worttrennung\}\}\n:([\w·]+),\s*\{\{Pl\.\}\}\s*([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}} {{Pl.}} {{kîte|de|$2|nivîs=na}}')
.replace(/\{\{Worttrennung\}\}\n:([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}}')
.replace(/·/g, '|')
.replace(/\s*\{\{Aussprache}}\s*/g, '\n')
.replace(/:\{\{IPA\}\}\s*\{\{Lautschrift\|([^\}]+)\}\}/g, '* {{IPA|de|[$1]}}')
.replace(/:\{\{Hörbeispiele\}\}\s*\{\{Audio\|([^\}]+)\}\}/g, '* {{deng|de|$1}}')
.replace(/,?\s*\{\{Audio\|([^\|]+)\|spr=at}}/g, '\n* {{deng|de|$1|dever=Awistirya}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[de:' + title + '|de.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'bnr û beralîkirin bike guharto',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr2?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=}}\n# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}')
.replace(/#B?E?R?A?L?Î?K?I?R?I?N? \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
// .replace(/# \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
}
});
pathoschild.TemplateScript.add({
name:'bikeKurdî',
accessKey: 'a',
script: function(editor) {
editor
.replace(/Central Iranian:/g, 'Îraniya merkezî')
.replace(/Northeastern Iranian:/g, 'Îraniya bakurêrojhilatî:')
.replace(/Southeastern Iranian:/g, 'Îraniya başûrêrojhilatî:')
.replace(/Northwestern Iranian:/g, 'Îraniya bakurêrojavayî:')
.replace(/Southwestern Iranian:/g, 'Îraniya başûrêrojavayî:')
.replace(/Munji-Yidgha:/g, 'Munjî-Yidghayî:')
.replace(/Kurdish:/g, 'Kurdî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Mazanderani-Shahmirzadi:/g, 'Mazenderanî-Şahmîrzadî:')
.replace(/Medo-Parthian:/g, 'Medo-partî:')
.replace(/\|kmr(\||\})/g, '|ku$1')
.replace(/\|g(\d+)?=m(\||\})/g, '|c$1=n$2')
.replace(/\|g(\d+)?=f(\||\})/g, '|c$1=m$2')
.replace(/\|g(\d+)?=n(\||\})/g, '|c$1=nt$2')
.replace(/\{\{(a|qualifier|qual|q)\|/g, '{{mj|')
.replace(/\{\{(s|sense)\|/g, '{{mane|')
.replace(/\{\{(af|affix)\|/g, '{{qertaf|')
.replace(/\{\{anagrams\|/g, '{{anagram|')
.replace(/\{\{also\|/g, '{{bnr-h|')
.replace(/\{\{(homophones|homophone|hmp)\|/g, '{{hevdeng|')
.replace(/\{\{(dbt|doublet)\|/g, '{{cotreh|')
.replace(/\{\{alter\|/g, '{{hw|')
.replace(/\{\{alt\|/g, '{{hw|')
.replace(/\{\{(synonyms|syn)\|/g, '{{hevmane|')
.replace(/\{\{(antonyms|antonym|ant)\|/g, '{{dijmane|')
.replace(/\{\{(hyponyms|hypo)\|/g, '{{jêrnav|')
.replace(/\{\{(hypernyms|hyper)\|/g, '{{jornav|')
.replace(/\{\{(coordinate terms|cot)\|/g, '{{koordîne|')
.replace(/\{\{(inline alt forms|alti)\|/g, '{{herwiha-rêz|')
.replace(/\{\{(hyphenation|hyph)\|/g, '{{kîte|')
.replace(/\{\{(back-form|back-formation|bf)\|/g, '{{paşvesazî|')
.replace(/\{\{l\|/g, '{{g|')
.replace(/\{\{m\|/g, '{{qal|')
.replace(/\{\{(label|lb)\|/g, '{{e|')
.replace(/\|(UK|RP)(\||\}\})/g, '|QY$2')
.replace(/\|AU(\||\}\})/g, '|Awistralya$1')
.replace(/\|Australia(\||\}\})/g, '|Awistralya$1')
.replace(/\|mul(\||\}\})/g, '|navz$1')
.replace(/\|Canada(\||\}\})/g, '|Kanada$1')
.replace(/\|informal(\||\}\})/g, '|neresmî$1')
.replace(/\|rare(\||\}\})/g, '|kêmpeyda$1')
.replace(/\|archaic(\||\}\})/g, '|kevnare$1')
.replace(/\|slang(\||\}\})/g, '|argo$1')
.replace(/\|idiomatic(\||\}\})/g, '|biwêjî$1')
.replace(/\|obsolete(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|dated(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|(US|USA|GenAm|GA)(\||\}\})/g, '\|DYA$2')
.replace(/\{\{audio\|/g, '{{deng|')
.replace(/\|[ ]*a[ ]*=[ ]*(US|USA|GA|GenAm)/g, '|dever=DYA')
.replace(/\|[ ]*a[ ]*=[ ]*Southern England/g, '|dever=Îngilistana başûr')
.replace(/\|[ ]*a[ ]*=[ ]*(UK|RP)/g, '|dever=QY')
.replace(/\|[ ]*a[ ]*=[ ]*AU/g, '|dever=Awistralya')
.replace(/[aA]udio \((UK|RP)\)/g, 'Deng (QY\)')
.replace(/\|[aA]udio \(Southern England\)\}\}/g, '\|Deng \(Îngilistana başûr\)}\}')
.replace(/[aA]udio \(AU\)/g, 'Deng \(Awistralya\)')
.replace(/[aA]udio \((US|USA|GA|GenAm)\)/g, 'Deng \(DYA\)')
.replace(/===(=)?(=)?Verb===(=)?(=)?\n{{head\|en\|verb form}}/g, '=== Formeke lêkerê ===\n{{lêker|en|form=erê}}')
.replace(/===(=)?(=)?Noun===(=)?(=)?\n{{head\|en\|noun form}}/g, '=== Formeke navdêrê ===\n{{navdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adjective===(=)?(=)?\n{{head\|en\|(comparative|superlative) adjective}}/g, '=== Formeke rengdêrê ===\n{{rengdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adverb===(=)?(=)?\n{{head\|en\|(comparative|superlative) adverb}}/g, '=== Formeke hokerê ===\n{{hoker|en|form=erê}}')
.replace(/===(=)?(=)?Synonyms===(=)?(=)?/g, '==== Hevmane ====')
.replace(/===(=)?(=)?Coordinate terms===(=)?(=)?/g, '==== Termên koordîne ====')
.replace(/===(=)?(=)?Antonyms===(=)?(=)?/g, '==== Dijmane ====')
.replace(/===(=)?(=)?Descendants===(=)?(=)?/g, '==== Dûnde ====')
.replace(/===(=)?(=)?Derived terms===(=)?(=)?/g, '==== Jê ====')
.replace(/===(=)?(=)?Alternative forms===(=)?(=)?/g, '==== Herwiha ====')
.replace(/===(=)?(=)?Related terms===(=)?(=)?/g, '==== Têkildar ====')
.replace(/===(=)?(=)?See also===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Anagrams===(=)?(=)?/g, '==== Anagram ====')
.replace(/===(=)?(=)?Further reading===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Pronunciation(.*?)===(=)?(=)?/g, '=== Bilêvkirin ===')
.replace(/===(=)?(=)?Etymology(.*?)===(=)?(=)?/g, '==== Etîmolojî ====')
.replace(/===(=)?(=)?Hyponyms===(=)?(=)?/g, '==== Jêrnav ====')
.replace(/===(=)?(=)?Hypernyms===(=)?(=)?/g, '==== Jornav ====')
.replace(/===(=)?(=)?Proper (n|N)oun===(=)?(=)?/g, '=== Serenav ===')
.replace(/===(=)?(=)?Adjective===(=)?(=)?/g, '=== Rengdêr ===')
.replace(/===(=)?(=)?Adverb===(=)?(=)?/g, '=== Hoker ===')
.replace(/===(=)?(=)?Verb===(=)?(=)?/g, '=== Lêker ===')
.replace(/===(=)?(=)?Noun===(=)?(=)?/g, '=== Navdêr ===')
.replace(/==English==/g, '== {\{ziman|en\}\} ==')
.replace(/\{\{en-noun(.*?)/g, '{{en-navdêr$1')
.replace(/\{\{en-verb(.*?)/g, '{{en-lêker$1')
.replace(/\{\{en-adv(.*?)/g, '{{en-hoker$1')
.replace(/\{\{en-adj(.*?)/g, '{{en-rengdêr$1')
.replace(/\{\{en-proper noun(.*?)/g, '{{en-serenav$1')
.replace(/\{\{en-plural( |\-)noun\}\}/g, '{{navdêr|en|j=p}}')
.replace(/\{\{(pre|prefix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêş\|$2\|$3-\|$4\}\}\.')
.replace(/\{\{(suf|suffix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{paş\|$2\|$3\|-$4\}\}\.')
.replace(/\{\{(com|compound)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêk\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(con|confix)\|/g, 'Ji \{\{pêşûpaş|')
.replace(/\n# \{\{(alt|alternative) (spelling|form)( of)?\|/g, '# {{awayekî din|')
.replace(/\{\{(wp|wikipedia)\}\}/g, '{{wp|ziman=en}}')
.replace(/\{\{(pedia|pedialite)\}\}/g, '{{wpedî|ziman=en}}')
.replace(/\{\{(der|rel|col)\d\|/g, '{{kol3|')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol(2|3)\|en/g, '==== $1 ====\n{{kol$2|en|cure=$1')
.replace(/\n# \{\{infl of\|en\|(.*?)\|\|ing-form\}\}/g, '# {{partîsîpa niha|en|$1}}')
.replace(/\n# \{\{past participle of\|en\|(.*?)\|nocat=1\}\}/g, '# {{partîsîpa borî|en|$1}}')
.replace(/\n# \{\{en-past of\|/g, '# {{en-dema-borî|')
.replace(/\n# \{\{en-simple past of\|/g, '# {{en-dema-borî-sade|')
.replace(/\n# \{\{en-third-person singular of\|(.*?)\}\}/g, '# {{en-dema-niha|$1|sêyem|yekjimar}}')
.replace(/\n# \{\{plural of\|/g, '# {{pirjimar|')
.replace(/\n# \{\{en-superlative of\|/g, '# {{sûperlatîv|en|')
.replace(/\n# \{\{en-comparative of\|/g, '# {{komparatîv|en|')
.replace(/\n# \{\{(obs|obsolete|dated) (spelling|form)( of)\|/g, '# {{kevnbûyî|')
.replace(/\{\{bor\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{deyn|$2|$1$3')
.replace(/\{\{inh\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{mîr|$2|$1$3')
.replace(/\{\{u?der\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{ji|$2|$1$3')
.replace(/\{\{etyl\|(.*?)\|(.*?)\}\}/g, '{{ji|$1|$2|-}}')
.replace(/\{\{(cog|cognate)\|/g, '{{hv|')
.replace(/\{\{(noncognate|noncog|ncog|nc)\|/g, '{{nehevreh|')
.replace(/\{\{surf\|/g, '{{anlz|')
.replace(/\{\{desc\|/g, '{{dû|')
.replace(/\{\{desctree\|/g, '{{dardû|')
.replace(/bor=1/g, 'deyn=1')
.replace(/nocat=1/g, 'nekat=1')
.replace(/\|(t|gloss)([1-9][0-9]*)?=/g, '|w$2=')
.replace(/\|alt([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/\|head([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/bor=1/g, 'deyn=1')
.replace(/\[\[(Image|File):/g, '\[\[Wêne:')
.replace(/\*[ ]*?\[\[(.*)\]\]/g, '* {{g|en|$1}}')
.replace(/#\*[ ]*?'''([0-9]+)''' (.*?)\n#(\*)?:(.+)/g, '#* $4 {{jêder|$2, $1}}')
.replace(/=\nFrom/g, '=\nJi')
.replace(/}(,)? from {/g, '}, ji {')
.replace(/=\nBorrowed from/g, '=\nDeyn ji')
.replace(/(e|E)quivalent to( Ji)?/g, 'wekheva')
.replace(/}\.\.\n/g, '}.\n')
.replace(/\.[ ]*?wekheva/g, '. Wekheva')
.replace(/Ji Ji/g, 'Ji')
.replace(/<t:/g, '<w:')
.replace(/<g:/g, '<c:')
// jê bibe
.replace(/\{\{see desc\}\}/g, '')
.replace(/\n\* \{\{rhymes(.+)/g, '')
.replace(/\n\{\{was wotd(.+)/g, '')
.replace(/\n\{\{root\|(.+)(\n)?/g, '')
.replace(/{{enPR\|[^( |\n|,)]+/g, '')
.replace(/\|-}} {{qal\|([^\|]+)\|/g, '|')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:' + title + '|en.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'reformat',
forNamespaces: '0',
accessKey: 'q',
script: function(editor) {
editor
.replace(/\[\[([^\]]+)\]\]\s*(>|→)\s*\[\[([^\]]+)\]\]/g, '\n#: {{qfnim|ku|$1|$3}}')
.replace(/{{ji\|fr}} \[\[([^\]]+)\]\]/g, '{{deyn|fr|ku|$1}}')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[([^\]]+)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\-\]\] \+ \[\[([^\]]+)\]\](\.''|''\.|'')?/g, 'Ji {{navg|ku|$3|-$4-|$5}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\-\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêş|ku|$3-|$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{paş|ku|$3|-$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêk|ku|$3|$4}}.')
.replace(/\* Jihevqetandin: (.+)/g, '* {{ku-kîte}}')
.replace(/==== Ji wêjeyê ====([\s\S]*?)\((.*?)\)\n\n=/g, '==== Ji wêjeyê ====$1{{jêder|$2}}\n\n=')
.replace(/==== Ji wêjeyê ====\n(.+)\n\n{{jêder\|/g, '==== Ji wêjeyê ====\n\* $1 {{jêder|')
.replace(/===(=)?[ ]*?Bi soranî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|ckb}}:')
.replace(/===(=)?[ ]*?Bi zazakî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|zza}}:')
.replace(/''Bin(ê|e)re'': '''\[\[(.*?)\]\]'''/g, '{{guharto|ku|$2}}')
.replace(/fr(e|a)nsî \[\[([^\]]+)\]\](,)? ji latînî \[\[([^\]]+)\]\]/g, '{{ji|fr|ku|$2}}, ji {{ji|la|ku|$4}}')
.replace(/#[ ]*?\{\{bnr(2)?\|(.*?)\}\}(\n\n====[ ]*?Etîmolojî[ ]*?====)?/g, '# {{mane?|ku}}\n\n==== Etîmolojî ====')
.replace(/\{\{bnr(2)?\|(.*?)\}\}(\n\n\[\[Kategorî:Kurdî\]\])?/g, '\n# {{guharto|ku|$2}}')
.replace(/(îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî) \[\[([^\]]+)\]\]/g, '{{hv|{{subst:koda zimanî|$1}}|$2}}')
// .replace(/\[\[([^\]]+)\]\] ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$2}}|$1}}')
// .replace(/\[\[([^\]]+)\]\] \(([^\)]+)\) ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$3}}|$1|tr=$2}}')
.replace(/(avestayî|pehlewî|akadî) \'\'([^\']+)\'\'/g, '{{hv|{{subst:koda zimanî|$1}}||$2|sc=Latn}}')
.replace(/\|îbrî}}/g, '|îbranî}}')
.replace(/(soranî|farisî) {{g\|(ckb|fa)\|([^\}\}]+)}} \(([^\)]+)\)/g, '{{hv|$2|$3|tr=$4}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|ckb|$1|tr=$2}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|fa|$1|tr=$2}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|ckb|$1}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|fa|$1}}')
.replace(/\[\[hevreh\]\]a/g, 'hevreha')
.replace(/\[\[Şablon:(.*?)\|(.*?) (p|r)\.(.*?)\]\]/g, '\n* {{$1|r=$4}}')
.replace(/\[\[Şablon:(.*?)\]\]/g, '\n* {{$1}}')
.replace(/\*[ ]*?\[\[volapûkî\]\]/g, '* {{Z|vo}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\] \(([^\)]+)\)/g, '* {{Z|$1}}: {{W-|$1|$2|tr=$3}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\]/g, '* {{Z|$1}}: {{W-|$1|$2}}')
.replace(/'''(.*?)''':\n{{werger-ser}}/g, '{{werger-ser|$1}}')
.replace(/=== Bilêvkirin ===[ ]*?\n(\*\n[ ]*?)?\n/g, '')
.replace(/==== Bikaranîn ====\n{{\((\|vn=no)?}}/g, '==== Jê ====\n{{($1}}')
.replace(/==== Herwiha ====[ ]*?\n\*[ ]*?\n\n==== Jê ====[ ]*?\n\*[ ]*?\n\n==== Etîmolojî ====[ ]*?/g, '')
.replace(/\*[ ]*?{{ku-ar}}: {{ku-Arab\|\[\[(.*?)\]\]}}/g, '* {{ku-ar}}: {{g|ku|$1|sc=ku-Arab|tr=-}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3|$4}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1}}')
.replace(/\n#:[ ]*?{{hevmane\|ku\|(.*?)}}(,)?[ ]*?\n#:[ ]*?{{hevmane\|ku\|(.*?)}}/g, '\n#: {{hevmane|ku|$1|$3}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}$3\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*/g, '* {{mj|$1}}')
.replace(/\n\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[(.*)\]\]/g, '\n* {{mj|$1}} {{g|ku|$2}}')
.replace(/\n\*[ ]*?\[\[(.*)\]\]/g, '\n* {{g|ku|$1}}')
.replace(/\n(\*|#|#\*|#:)([^( |#\* |#: )])/g, '\n$1 $2')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/,/g, ', ')
.replace(/ ,/g, ',')
.replace(/ [ ]*?/g, ' ')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[z(e|i)lam\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|law}} e.')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[(keç|jin)\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|keç}} e.')
.replace(/(#)?\*?:?[ ]*?''(.*?)''[ ]*?{{jêder\|/g, '$1* {{jêder|ku|jêgirtin=$2|')
.replace(/jêgirtin= /g, 'jêgirtin=')
.replace(/'''[ ]*?Bi (zaravayên din|zazakî)[ ]*?'''/g, '==== Bi zaravayên din ====')
.replace(/Zazakî:/g, '* {{Z|zza}}:')
.replace(/{{navdêr\|ku\|c=-}}/g, '{{ku-tewîn-nav|{{subst:PAGENAME}}|-}}\n{{navdêr|ku|c=m}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin')
.clickDiff();
}
});
pathoschild.TemplateScript.add([
// add your own templates or scripts here
{
name: 'template n',
template: '=={{=nn|{{ucfirst:{{navê zimanî|' + modifiedTitle + '}}}}|' + modifiedTitle + '}}==<noinclude>[[Kategorî:Wîkîferheng:Sernavên zimanan]]</noinclude>',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:=nn|=nn]]}}',
forNamespaces: '10'
},
{
name: 'înterwîkî-çêke',
template: '{{subst:înterwîkî-çêke}}',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:înterwîkî-çêke|subst:înterwîkî-çêke]]}}',
forNamespaces: '14'
},
{
name: 'zimankatbike',
template: '{{zimankatbike|}}',
position: 'cursor',
accessKey: 'f',
forNamespaces: '14'
},
{
category: 'sererastkirin',
name: 'tewîn',
template: '{{ku-tewîn-nav|{{subst:PAGENAME}}|mê}}',
accessKey: '4',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'guharto',
template: '# {{guharto|}}',
position: 'cursor',
accessKey: '',
editSummary: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab|cure=navdêr|c=z|m=m|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab-lêker',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab-lêker|c=h-gh|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'rengdêr',
template: '{{subst:Bikarhêner:Wikihez/preload-rengdêr|ziman=ku|cure=rengdêr}}',
position: 'cursor',
accessKey: '2',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'gp',
template: '{{subst:Bikarhêner:Wikihez/preload-gp}}',
position: 'cursor',
editSummary: '',
forNamespaces: '0'
},
{
category: 'gotûbêj',
name: 'ragihandin',
template: ':{{r| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'outdent',
template: '{{outdent| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'ds',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=standardkirinê|2=DS|meh=Çîriya paşîn|dp=ds|peyitandî=standardkirin|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '1',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'dp',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=peyitandinê|2=DP|meh=Çîriya paşîn|dp=dp|peyitandî=peyitandî|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '2',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'arşîvbin',
template: '{{arşîv-bin}}',
position: 'cursor',
editSummary: 'a',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'xêrhatin',
template: '{{subst:şablon:bixêrhatin/preload}}',
position: 'cursor',
editSummary: 'xêrhatin lê zêde kir',
forNamespaces: 'user talk'
},
{
name: 'nepeyitandî',
template: ':{{nepeyitandî}}--~~~~',
position: 'after',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +{{[[şablon:nepeyitandî|nepeyitandî]]}}',
forNamespaces: '4',
script: function(editor) {
editor
.replace(/== \[\[(.*?)\]\] ==/g, '== <s>\[\[$1\]\]</s> ==');
}
},
{
name: 'jinûvesazî',
template: '{{subst:Bikarhêner:Wikihez/jinûvesazî|ziman=ine-pro|cure=navdêr|peyv= }}',
position: 'cursor',
editSummary: '',
accessKey: '1',
forNamespaces: '108'
},
]);
});
// </nowiki>
7t58ybrtr3n3cnhbrry2n5ow1t5v7hr
6241922
6241921
2026-07-12T22:33:57Z
Wikihez
7344
6241922
javascript
text/javascript
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
var title = mw.config.get('wgTitle');
// Remove '=' from the title using the replace method
var modifiedTitle = title.replace(/=/g, '');
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
pathoschild.TemplateScript.add({
name:'kolon',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/{{\)}}/g, '}}')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '|$2<q:$1>')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$3<q:$1>')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$2')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '|$1')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'nimûne',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/#:\s*'{2}(.*?)'{2}\n/g, '#: {{nm|tr|$1|rêz=1}}\n')
.replace(/#:\s*'{2}(.*?)'{2}\s*\(([^\)]+)\)\.?\n/g, '#: {{nm|tr|$1|$2|rêz=1}}\n')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Formata [[Şablon:nimûne|nimûneyan]]+')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'parentez bike îzah',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\(([^\)]+)\)/g, '{{îzah|$1}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'bnr bike ku-Latn',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr(2)?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=-}}\n# {{ku-Latn|$2}}\n\n==== Bi alfabeyên din ====\n* {{ku-ar|' + title + '}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: [[Şablon:ku-Latn|{{ku-Latn}}]]+')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'herwiha',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$2||$1}}')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '| {{hw|ku|$2}}')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$1}}')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'ji dewikt',
// forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{Worttrennung\}\}\n:([\w·]+),\s*\{\{Pl\.\}\}\s*([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}} {{Pl.}} {{kîte|de|$2|nivîs=na}}')
.replace(/\{\{Worttrennung\}\}\n:([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}}')
.replace(/·/g, '|')
.replace(/\s*\{\{Aussprache}}\s*/g, '\n')
.replace(/:\{\{IPA\}\}\s*\{\{Lautschrift\|([^\}]+)\}\}/g, '* {{IPA|de|[$1]}}')
.replace(/:\{\{Hörbeispiele\}\}\s*\{\{Audio\|([^\}]+)\}\}/g, '* {{deng|de|$1}}')
.replace(/,?\s*\{\{Audio\|([^\|]+)\|spr=at}}/g, '\n* {{deng|de|$1|dever=Awistirya}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[de:' + title + '|de.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'bnr û beralîkirin bike guharto',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr2?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=}}\n# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}')
.replace(/#B?E?R?A?L?Î?K?I?R?I?N? \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
// .replace(/# \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
}
});
pathoschild.TemplateScript.add({
name:'bikeKurdî',
accessKey: 'a',
script: function(editor) {
editor
.replace(/Central Iranian:/g, 'Îraniya merkezî')
.replace(/Northeastern Iranian:/g, 'Îraniya bakurêrojhilatî:')
.replace(/Southeastern Iranian:/g, 'Îraniya başûrêrojhilatî:')
.replace(/Northwestern Iranian:/g, 'Îraniya bakurêrojavayî:')
.replace(/Southwestern Iranian:/g, 'Îraniya başûrêrojavayî:')
.replace(/Munji-Yidgha:/g, 'Munjî-Yidghayî:')
.replace(/Kurdish:/g, 'Kurdî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Mazanderani-Shahmirzadi:/g, 'Mazenderanî-Şahmîrzadî:')
.replace(/Medo-Parthian:/g, 'Medo-partî:')
.replace(/\|kmr(\||\})/g, '|ku$1')
.replace(/\|g(\d+)?=m(\||\})/g, '|c$1=n$2')
.replace(/\|g(\d+)?=f(\||\})/g, '|c$1=m$2')
.replace(/\|g(\d+)?=n(\||\})/g, '|c$1=nt$2')
.replace(/\{\{(a|qualifier|qual|q)\|/g, '{{mj|')
.replace(/\{\{(s|sense)\|/g, '{{mane|')
.replace(/\{\{(af|affix)\|/g, '{{qertaf|')
.replace(/\{\{anagrams\|/g, '{{anagram|')
.replace(/\{\{also\|/g, '{{bnr-h|')
.replace(/\{\{(homophones|homophone|hmp)\|/g, '{{hevdeng|')
.replace(/\{\{(dbt|doublet)\|/g, '{{cotreh|')
.replace(/\{\{alter\|/g, '{{hw|')
.replace(/\{\{alt\|/g, '{{hw|')
.replace(/\{\{(synonyms|syn)\|/g, '{{hevmane|')
.replace(/\{\{(antonyms|antonym|ant)\|/g, '{{dijmane|')
.replace(/\{\{(hyponyms|hypo)\|/g, '{{jêrnav|')
.replace(/\{\{(hypernyms|hyper)\|/g, '{{jornav|')
.replace(/\{\{(coordinate terms|cot)\|/g, '{{koordîne|')
.replace(/\{\{(inline alt forms|alti)\|/g, '{{herwiha-rêz|')
.replace(/\{\{(hyphenation|hyph)\|/g, '{{kîte|')
.replace(/\{\{(back-form|back-formation|bf)\|/g, '{{paşvesazî|')
.replace(/\{\{l\|/g, '{{g|')
.replace(/\{\{m\|/g, '{{qal|')
.replace(/\{\{(label|lb)\|/g, '{{e|')
.replace(/\|(UK|RP)(\||\}\})/g, '|QY$2')
.replace(/\|AU(\||\}\})/g, '|Awistralya$1')
.replace(/\|Australia(\||\}\})/g, '|Awistralya$1')
.replace(/\|mul(\||\}\})/g, '|navz$1')
.replace(/\|Canada(\||\}\})/g, '|Kanada$1')
.replace(/\|informal(\||\}\})/g, '|neresmî$1')
.replace(/\|rare(\||\}\})/g, '|kêmpeyda$1')
.replace(/\|archaic(\||\}\})/g, '|kevnare$1')
.replace(/\|slang(\||\}\})/g, '|argo$1')
.replace(/\|idiomatic(\||\}\})/g, '|biwêjî$1')
.replace(/\|obsolete(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|dated(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|(US|USA|GenAm|GA)(\||\}\})/g, '\|DYA$2')
.replace(/\{\{audio\|/g, '{{deng|')
.replace(/\|[ ]*a[ ]*=[ ]*(US|USA|GA|GenAm)/g, '|dever=DYA')
.replace(/\|[ ]*a[ ]*=[ ]*Southern England/g, '|dever=Îngilistana başûr')
.replace(/\|[ ]*a[ ]*=[ ]*(UK|RP)/g, '|dever=QY')
.replace(/\|[ ]*a[ ]*=[ ]*AU/g, '|dever=Awistralya')
.replace(/[aA]udio \((UK|RP)\)/g, 'Deng (QY\)')
.replace(/\|[aA]udio \(Southern England\)\}\}/g, '\|Deng \(Îngilistana başûr\)}\}')
.replace(/[aA]udio \(AU\)/g, 'Deng \(Awistralya\)')
.replace(/[aA]udio \((US|USA|GA|GenAm)\)/g, 'Deng \(DYA\)')
.replace(/===(=)?(=)?Verb===(=)?(=)?\n{{head\|en\|verb form}}/g, '=== Formeke lêkerê ===\n{{lêker|en|form=erê}}')
.replace(/===(=)?(=)?Noun===(=)?(=)?\n{{head\|en\|noun form}}/g, '=== Formeke navdêrê ===\n{{navdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adjective===(=)?(=)?\n{{head\|en\|(comparative|superlative) adjective}}/g, '=== Formeke rengdêrê ===\n{{rengdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adverb===(=)?(=)?\n{{head\|en\|(comparative|superlative) adverb}}/g, '=== Formeke hokerê ===\n{{hoker|en|form=erê}}')
.replace(/===(=)?(=)?Synonyms===(=)?(=)?/g, '==== Hevmane ====')
.replace(/===(=)?(=)?Coordinate terms===(=)?(=)?/g, '==== Termên koordîne ====')
.replace(/===(=)?(=)?Antonyms===(=)?(=)?/g, '==== Dijmane ====')
.replace(/===(=)?(=)?Descendants===(=)?(=)?/g, '==== Dûnde ====')
.replace(/===(=)?(=)?Derived terms===(=)?(=)?/g, '==== Jê ====')
.replace(/===(=)?(=)?Alternative forms===(=)?(=)?/g, '==== Herwiha ====')
.replace(/===(=)?(=)?Related terms===(=)?(=)?/g, '==== Têkildar ====')
.replace(/===(=)?(=)?See also===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Anagrams===(=)?(=)?/g, '==== Anagram ====')
.replace(/===(=)?(=)?Further reading===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Pronunciation(.*?)===(=)?(=)?/g, '=== Bilêvkirin ===')
.replace(/===(=)?(=)?Etymology(.*?)===(=)?(=)?/g, '==== Etîmolojî ====')
.replace(/===(=)?(=)?Hyponyms===(=)?(=)?/g, '==== Jêrnav ====')
.replace(/===(=)?(=)?Hypernyms===(=)?(=)?/g, '==== Jornav ====')
.replace(/===(=)?(=)?Proper (n|N)oun===(=)?(=)?/g, '=== Serenav ===')
.replace(/===(=)?(=)?Adjective===(=)?(=)?/g, '=== Rengdêr ===')
.replace(/===(=)?(=)?Adverb===(=)?(=)?/g, '=== Hoker ===')
.replace(/===(=)?(=)?Verb===(=)?(=)?/g, '=== Lêker ===')
.replace(/===(=)?(=)?Noun===(=)?(=)?/g, '=== Navdêr ===')
.replace(/^==\s*([^=]+)\s*==$/g, '== {{ziman|{{subst:koda zimanî/en}}}} ==')
.replace(/\{\{en-noun(.*?)/g, '{{en-navdêr$1')
.replace(/\{\{en-verb(.*?)/g, '{{en-lêker$1')
.replace(/\{\{en-adv(.*?)/g, '{{en-hoker$1')
.replace(/\{\{en-adj(.*?)/g, '{{en-rengdêr$1')
.replace(/\{\{en-proper noun(.*?)/g, '{{en-serenav$1')
.replace(/\{\{en-plural( |\-)noun\}\}/g, '{{navdêr|en|j=p}}')
.replace(/\{\{(pre|prefix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêş\|$2\|$3-\|$4\}\}\.')
.replace(/\{\{(suf|suffix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{paş\|$2\|$3\|-$4\}\}\.')
.replace(/\{\{(com|compound)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêk\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(con|confix)\|/g, 'Ji \{\{pêşûpaş|')
.replace(/\n# \{\{(alt|alternative) (spelling|form)( of)?\|/g, '# {{awayekî din|')
.replace(/\{\{(wp|wikipedia)\}\}/g, '{{wp|ziman=en}}')
.replace(/\{\{(pedia|pedialite)\}\}/g, '{{wpedî|ziman=en}}')
.replace(/\{\{(der|rel|col)\d\|/g, '{{kol3|')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol(2|3)\|en/g, '==== $1 ====\n{{kol$2|en|cure=$1')
.replace(/\n# \{\{infl of\|en\|(.*?)\|\|ing-form\}\}/g, '# {{partîsîpa niha|en|$1}}')
.replace(/\n# \{\{past participle of\|en\|(.*?)\|nocat=1\}\}/g, '# {{partîsîpa borî|en|$1}}')
.replace(/\n# \{\{en-past of\|/g, '# {{en-dema-borî|')
.replace(/\n# \{\{en-simple past of\|/g, '# {{en-dema-borî-sade|')
.replace(/\n# \{\{en-third-person singular of\|(.*?)\}\}/g, '# {{en-dema-niha|$1|sêyem|yekjimar}}')
.replace(/\n# \{\{plural of\|/g, '# {{pirjimar|')
.replace(/\n# \{\{en-superlative of\|/g, '# {{sûperlatîv|en|')
.replace(/\n# \{\{en-comparative of\|/g, '# {{komparatîv|en|')
.replace(/\n# \{\{(obs|obsolete|dated) (spelling|form)( of)\|/g, '# {{kevnbûyî|')
.replace(/\{\{bor\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{deyn|$2|$1$3')
.replace(/\{\{inh\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{mîr|$2|$1$3')
.replace(/\{\{u?der\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{ji|$2|$1$3')
.replace(/\{\{etyl\|(.*?)\|(.*?)\}\}/g, '{{ji|$1|$2|-}}')
.replace(/\{\{(cog|cognate)\|/g, '{{hv|')
.replace(/\{\{(noncognate|noncog|ncog|nc)\|/g, '{{nehevreh|')
.replace(/\{\{surf\|/g, '{{anlz|')
.replace(/\{\{desc\|/g, '{{dû|')
.replace(/\{\{desctree\|/g, '{{dardû|')
.replace(/bor=1/g, 'deyn=1')
.replace(/nocat=1/g, 'nekat=1')
.replace(/\|(t|gloss)([1-9][0-9]*)?=/g, '|w$2=')
.replace(/\|alt([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/\|head([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/bor=1/g, 'deyn=1')
.replace(/\[\[(Image|File):/g, '\[\[Wêne:')
.replace(/\*[ ]*?\[\[(.*)\]\]/g, '* {{g|en|$1}}')
.replace(/#\*[ ]*?'''([0-9]+)''' (.*?)\n#(\*)?:(.+)/g, '#* $4 {{jêder|$2, $1}}')
.replace(/=\nFrom/g, '=\nJi')
.replace(/}(,)? from {/g, '}, ji {')
.replace(/=\nBorrowed from/g, '=\nDeyn ji')
.replace(/(e|E)quivalent to( Ji)?/g, 'wekheva')
.replace(/}\.\.\n/g, '}.\n')
.replace(/\.[ ]*?wekheva/g, '. Wekheva')
.replace(/Ji Ji/g, 'Ji')
.replace(/<t:/g, '<w:')
.replace(/<g:/g, '<c:')
// jê bibe
.replace(/\{\{see desc\}\}/g, '')
.replace(/\n\* \{\{rhymes(.+)/g, '')
.replace(/\n\{\{was wotd(.+)/g, '')
.replace(/\n\{\{root\|(.+)(\n)?/g, '')
.replace(/{{enPR\|[^( |\n|,)]+/g, '')
.replace(/\|-}} {{qal\|([^\|]+)\|/g, '|')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:' + title + '|en.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'reformat',
forNamespaces: '0',
accessKey: 'q',
script: function(editor) {
editor
.replace(/\[\[([^\]]+)\]\]\s*(>|→)\s*\[\[([^\]]+)\]\]/g, '\n#: {{qfnim|ku|$1|$3}}')
.replace(/{{ji\|fr}} \[\[([^\]]+)\]\]/g, '{{deyn|fr|ku|$1}}')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[([^\]]+)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\-\]\] \+ \[\[([^\]]+)\]\](\.''|''\.|'')?/g, 'Ji {{navg|ku|$3|-$4-|$5}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\-\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêş|ku|$3-|$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{paş|ku|$3|-$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêk|ku|$3|$4}}.')
.replace(/\* Jihevqetandin: (.+)/g, '* {{ku-kîte}}')
.replace(/==== Ji wêjeyê ====([\s\S]*?)\((.*?)\)\n\n=/g, '==== Ji wêjeyê ====$1{{jêder|$2}}\n\n=')
.replace(/==== Ji wêjeyê ====\n(.+)\n\n{{jêder\|/g, '==== Ji wêjeyê ====\n\* $1 {{jêder|')
.replace(/===(=)?[ ]*?Bi soranî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|ckb}}:')
.replace(/===(=)?[ ]*?Bi zazakî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|zza}}:')
.replace(/''Bin(ê|e)re'': '''\[\[(.*?)\]\]'''/g, '{{guharto|ku|$2}}')
.replace(/fr(e|a)nsî \[\[([^\]]+)\]\](,)? ji latînî \[\[([^\]]+)\]\]/g, '{{ji|fr|ku|$2}}, ji {{ji|la|ku|$4}}')
.replace(/#[ ]*?\{\{bnr(2)?\|(.*?)\}\}(\n\n====[ ]*?Etîmolojî[ ]*?====)?/g, '# {{mane?|ku}}\n\n==== Etîmolojî ====')
.replace(/\{\{bnr(2)?\|(.*?)\}\}(\n\n\[\[Kategorî:Kurdî\]\])?/g, '\n# {{guharto|ku|$2}}')
.replace(/(îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî) \[\[([^\]]+)\]\]/g, '{{hv|{{subst:koda zimanî|$1}}|$2}}')
// .replace(/\[\[([^\]]+)\]\] ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$2}}|$1}}')
// .replace(/\[\[([^\]]+)\]\] \(([^\)]+)\) ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$3}}|$1|tr=$2}}')
.replace(/(avestayî|pehlewî|akadî) \'\'([^\']+)\'\'/g, '{{hv|{{subst:koda zimanî|$1}}||$2|sc=Latn}}')
.replace(/\|îbrî}}/g, '|îbranî}}')
.replace(/(soranî|farisî) {{g\|(ckb|fa)\|([^\}\}]+)}} \(([^\)]+)\)/g, '{{hv|$2|$3|tr=$4}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|ckb|$1|tr=$2}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|fa|$1|tr=$2}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|ckb|$1}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|fa|$1}}')
.replace(/\[\[hevreh\]\]a/g, 'hevreha')
.replace(/\[\[Şablon:(.*?)\|(.*?) (p|r)\.(.*?)\]\]/g, '\n* {{$1|r=$4}}')
.replace(/\[\[Şablon:(.*?)\]\]/g, '\n* {{$1}}')
.replace(/\*[ ]*?\[\[volapûkî\]\]/g, '* {{Z|vo}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\] \(([^\)]+)\)/g, '* {{Z|$1}}: {{W-|$1|$2|tr=$3}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\]/g, '* {{Z|$1}}: {{W-|$1|$2}}')
.replace(/'''(.*?)''':\n{{werger-ser}}/g, '{{werger-ser|$1}}')
.replace(/=== Bilêvkirin ===[ ]*?\n(\*\n[ ]*?)?\n/g, '')
.replace(/==== Bikaranîn ====\n{{\((\|vn=no)?}}/g, '==== Jê ====\n{{($1}}')
.replace(/==== Herwiha ====[ ]*?\n\*[ ]*?\n\n==== Jê ====[ ]*?\n\*[ ]*?\n\n==== Etîmolojî ====[ ]*?/g, '')
.replace(/\*[ ]*?{{ku-ar}}: {{ku-Arab\|\[\[(.*?)\]\]}}/g, '* {{ku-ar}}: {{g|ku|$1|sc=ku-Arab|tr=-}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3|$4}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1}}')
.replace(/\n#:[ ]*?{{hevmane\|ku\|(.*?)}}(,)?[ ]*?\n#:[ ]*?{{hevmane\|ku\|(.*?)}}/g, '\n#: {{hevmane|ku|$1|$3}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}$3\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*/g, '* {{mj|$1}}')
.replace(/\n\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[(.*)\]\]/g, '\n* {{mj|$1}} {{g|ku|$2}}')
.replace(/\n\*[ ]*?\[\[(.*)\]\]/g, '\n* {{g|ku|$1}}')
.replace(/\n(\*|#|#\*|#:)([^( |#\* |#: )])/g, '\n$1 $2')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/,/g, ', ')
.replace(/ ,/g, ',')
.replace(/ [ ]*?/g, ' ')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[z(e|i)lam\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|law}} e.')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[(keç|jin)\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|keç}} e.')
.replace(/(#)?\*?:?[ ]*?''(.*?)''[ ]*?{{jêder\|/g, '$1* {{jêder|ku|jêgirtin=$2|')
.replace(/jêgirtin= /g, 'jêgirtin=')
.replace(/'''[ ]*?Bi (zaravayên din|zazakî)[ ]*?'''/g, '==== Bi zaravayên din ====')
.replace(/Zazakî:/g, '* {{Z|zza}}:')
.replace(/{{navdêr\|ku\|c=-}}/g, '{{ku-tewîn-nav|{{subst:PAGENAME}}|-}}\n{{navdêr|ku|c=m}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin')
.clickDiff();
}
});
pathoschild.TemplateScript.add([
// add your own templates or scripts here
{
name: 'template n',
template: '=={{=nn|{{ucfirst:{{navê zimanî|' + modifiedTitle + '}}}}|' + modifiedTitle + '}}==<noinclude>[[Kategorî:Wîkîferheng:Sernavên zimanan]]</noinclude>',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:=nn|=nn]]}}',
forNamespaces: '10'
},
{
name: 'înterwîkî-çêke',
template: '{{subst:înterwîkî-çêke}}',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:înterwîkî-çêke|subst:înterwîkî-çêke]]}}',
forNamespaces: '14'
},
{
name: 'zimankatbike',
template: '{{zimankatbike|}}',
position: 'cursor',
accessKey: 'f',
forNamespaces: '14'
},
{
category: 'sererastkirin',
name: 'tewîn',
template: '{{ku-tewîn-nav|{{subst:PAGENAME}}|mê}}',
accessKey: '4',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'guharto',
template: '# {{guharto|}}',
position: 'cursor',
accessKey: '',
editSummary: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab|cure=navdêr|c=z|m=m|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab-lêker',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab-lêker|c=h-gh|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'rengdêr',
template: '{{subst:Bikarhêner:Wikihez/preload-rengdêr|ziman=ku|cure=rengdêr}}',
position: 'cursor',
accessKey: '2',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'gp',
template: '{{subst:Bikarhêner:Wikihez/preload-gp}}',
position: 'cursor',
editSummary: '',
forNamespaces: '0'
},
{
category: 'gotûbêj',
name: 'ragihandin',
template: ':{{r| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'outdent',
template: '{{outdent| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'ds',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=standardkirinê|2=DS|meh=Çîriya paşîn|dp=ds|peyitandî=standardkirin|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '1',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'dp',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=peyitandinê|2=DP|meh=Çîriya paşîn|dp=dp|peyitandî=peyitandî|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '2',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'arşîvbin',
template: '{{arşîv-bin}}',
position: 'cursor',
editSummary: 'a',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'xêrhatin',
template: '{{subst:şablon:bixêrhatin/preload}}',
position: 'cursor',
editSummary: 'xêrhatin lê zêde kir',
forNamespaces: 'user talk'
},
{
name: 'nepeyitandî',
template: ':{{nepeyitandî}}--~~~~',
position: 'after',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +{{[[şablon:nepeyitandî|nepeyitandî]]}}',
forNamespaces: '4',
script: function(editor) {
editor
.replace(/== \[\[(.*?)\]\] ==/g, '== <s>\[\[$1\]\]</s> ==');
}
},
{
name: 'jinûvesazî',
template: '{{subst:Bikarhêner:Wikihez/jinûvesazî|ziman=ine-pro|cure=navdêr|peyv= }}',
position: 'cursor',
editSummary: '',
accessKey: '1',
forNamespaces: '108'
},
]);
});
// </nowiki>
0xpskle5c9756emp1b36mgjfg48qau7
6241923
6241922
2026-07-12T22:39:16Z
Wikihez
7344
6241923
javascript
text/javascript
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
var title = mw.config.get('wgTitle');
// Remove '=' from the title using the replace method
var modifiedTitle = title.replace(/=/g, '');
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
pathoschild.TemplateScript.add({
name:'kolon',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/{{\)}}/g, '}}')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '|$2<q:$1>')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$3<q:$1>')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$2')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '|$1')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'nimûne',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/#:\s*'{2}(.*?)'{2}\n/g, '#: {{nm|tr|$1|rêz=1}}\n')
.replace(/#:\s*'{2}(.*?)'{2}\s*\(([^\)]+)\)\.?\n/g, '#: {{nm|tr|$1|$2|rêz=1}}\n')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Formata [[Şablon:nimûne|nimûneyan]]+')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'parentez bike îzah',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\(([^\)]+)\)/g, '{{îzah|$1}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'bnr bike ku-Latn',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr(2)?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=-}}\n# {{ku-Latn|$2}}\n\n==== Bi alfabeyên din ====\n* {{ku-ar|' + title + '}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: [[Şablon:ku-Latn|{{ku-Latn}}]]+')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'herwiha',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$2||$1}}')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '| {{hw|ku|$2}}')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$1}}')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'ji dewikt',
// forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{Worttrennung\}\}\n:([\w·]+),\s*\{\{Pl\.\}\}\s*([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}} {{Pl.}} {{kîte|de|$2|nivîs=na}}')
.replace(/\{\{Worttrennung\}\}\n:([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}}')
.replace(/·/g, '|')
.replace(/\s*\{\{Aussprache}}\s*/g, '\n')
.replace(/:\{\{IPA\}\}\s*\{\{Lautschrift\|([^\}]+)\}\}/g, '* {{IPA|de|[$1]}}')
.replace(/:\{\{Hörbeispiele\}\}\s*\{\{Audio\|([^\}]+)\}\}/g, '* {{deng|de|$1}}')
.replace(/,?\s*\{\{Audio\|([^\|]+)\|spr=at}}/g, '\n* {{deng|de|$1|dever=Awistirya}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[de:' + title + '|de.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'bnr û beralîkirin bike guharto',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr2?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=}}\n# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}')
.replace(/#B?E?R?A?L?Î?K?I?R?I?N? \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
// .replace(/# \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
}
});
pathoschild.TemplateScript.add({
name:'bikeKurdî',
accessKey: 'a',
script: function(editor) {
editor
.replace(/Central Iranian:/g, 'Îraniya merkezî')
.replace(/Northeastern Iranian:/g, 'Îraniya bakurêrojhilatî:')
.replace(/Southeastern Iranian:/g, 'Îraniya başûrêrojhilatî:')
.replace(/Northwestern Iranian:/g, 'Îraniya bakurêrojavayî:')
.replace(/Southwestern Iranian:/g, 'Îraniya başûrêrojavayî:')
.replace(/Munji-Yidgha:/g, 'Munjî-Yidghayî:')
.replace(/Kurdish:/g, 'Kurdî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Mazanderani-Shahmirzadi:/g, 'Mazenderanî-Şahmîrzadî:')
.replace(/Medo-Parthian:/g, 'Medo-partî:')
.replace(/\|kmr(\||\})/g, '|ku$1')
.replace(/\|g(\d+)?=m(\||\})/g, '|c$1=n$2')
.replace(/\|g(\d+)?=f(\||\})/g, '|c$1=m$2')
.replace(/\|g(\d+)?=n(\||\})/g, '|c$1=nt$2')
.replace(/\{\{(a|qualifier|qual|q)\|/g, '{{mj|')
.replace(/\{\{(s|sense)\|/g, '{{mane|')
.replace(/\{\{(af|affix)\|/g, '{{qertaf|')
.replace(/\{\{anagrams\|/g, '{{anagram|')
.replace(/\{\{also\|/g, '{{bnr-h|')
.replace(/\{\{(homophones|homophone|hmp)\|/g, '{{hevdeng|')
.replace(/\{\{(dbt|doublet)\|/g, '{{cotreh|')
.replace(/\{\{alter\|/g, '{{hw|')
.replace(/\{\{alt\|/g, '{{hw|')
.replace(/\{\{(synonyms|syn)\|/g, '{{hevmane|')
.replace(/\{\{(antonyms|antonym|ant)\|/g, '{{dijmane|')
.replace(/\{\{(hyponyms|hypo)\|/g, '{{jêrnav|')
.replace(/\{\{(hypernyms|hyper)\|/g, '{{jornav|')
.replace(/\{\{(coordinate terms|cot)\|/g, '{{koordîne|')
.replace(/\{\{(inline alt forms|alti)\|/g, '{{herwiha-rêz|')
.replace(/\{\{(hyphenation|hyph)\|/g, '{{kîte|')
.replace(/\{\{(back-form|back-formation|bf)\|/g, '{{paşvesazî|')
.replace(/\{\{l\|/g, '{{g|')
.replace(/\{\{m\|/g, '{{qal|')
.replace(/\{\{(label|lb)\|/g, '{{e|')
.replace(/\|(UK|RP)(\||\}\})/g, '|QY$2')
.replace(/\|AU(\||\}\})/g, '|Awistralya$1')
.replace(/\|Australia(\||\}\})/g, '|Awistralya$1')
.replace(/\|mul(\||\}\})/g, '|navz$1')
.replace(/\|Canada(\||\}\})/g, '|Kanada$1')
.replace(/\|informal(\||\}\})/g, '|neresmî$1')
.replace(/\|rare(\||\}\})/g, '|kêmpeyda$1')
.replace(/\|archaic(\||\}\})/g, '|kevnare$1')
.replace(/\|slang(\||\}\})/g, '|argo$1')
.replace(/\|idiomatic(\||\}\})/g, '|biwêjî$1')
.replace(/\|obsolete(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|dated(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|(US|USA|GenAm|GA)(\||\}\})/g, '\|DYA$2')
.replace(/\{\{audio\|/g, '{{deng|')
.replace(/\|[ ]*a[ ]*=[ ]*(US|USA|GA|GenAm)/g, '|dever=DYA')
.replace(/\|[ ]*a[ ]*=[ ]*Southern England/g, '|dever=Îngilistana başûr')
.replace(/\|[ ]*a[ ]*=[ ]*(UK|RP)/g, '|dever=QY')
.replace(/\|[ ]*a[ ]*=[ ]*AU/g, '|dever=Awistralya')
.replace(/[aA]udio \((UK|RP)\)/g, 'Deng (QY\)')
.replace(/\|[aA]udio \(Southern England\)\}\}/g, '\|Deng \(Îngilistana başûr\)}\}')
.replace(/[aA]udio \(AU\)/g, 'Deng \(Awistralya\)')
.replace(/[aA]udio \((US|USA|GA|GenAm)\)/g, 'Deng \(DYA\)')
.replace(/===(=)?(=)?Verb===(=)?(=)?\n{{head\|en\|verb form}}/g, '=== Formeke lêkerê ===\n{{lêker|en|form=erê}}')
.replace(/===(=)?(=)?Noun===(=)?(=)?\n{{head\|en\|noun form}}/g, '=== Formeke navdêrê ===\n{{navdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adjective===(=)?(=)?\n{{head\|en\|(comparative|superlative) adjective}}/g, '=== Formeke rengdêrê ===\n{{rengdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adverb===(=)?(=)?\n{{head\|en\|(comparative|superlative) adverb}}/g, '=== Formeke hokerê ===\n{{hoker|en|form=erê}}')
.replace(/===(=)?(=)?Synonyms===(=)?(=)?/g, '==== Hevmane ====')
.replace(/===(=)?(=)?Coordinate terms===(=)?(=)?/g, '==== Termên koordîne ====')
.replace(/===(=)?(=)?Antonyms===(=)?(=)?/g, '==== Dijmane ====')
.replace(/===(=)?(=)?Descendants===(=)?(=)?/g, '==== Dûnde ====')
.replace(/===(=)?(=)?Derived terms===(=)?(=)?/g, '==== Jê ====')
.replace(/===(=)?(=)?Alternative forms===(=)?(=)?/g, '==== Herwiha ====')
.replace(/===(=)?(=)?Related terms===(=)?(=)?/g, '==== Têkildar ====')
.replace(/===(=)?(=)?See also===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Anagrams===(=)?(=)?/g, '==== Anagram ====')
.replace(/===(=)?(=)?Further reading===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Pronunciation(.*?)===(=)?(=)?/g, '=== Bilêvkirin ===')
.replace(/===(=)?(=)?Etymology(.*?)===(=)?(=)?/g, '==== Etîmolojî ====')
.replace(/===(=)?(=)?Hyponyms===(=)?(=)?/g, '==== Jêrnav ====')
.replace(/===(=)?(=)?Hypernyms===(=)?(=)?/g, '==== Jornav ====')
.replace(/===(=)?(=)?Proper (n|N)oun===(=)?(=)?/g, '=== Serenav ===')
.replace(/===(=)?(=)?Adjective===(=)?(=)?/g, '=== Rengdêr ===')
.replace(/===(=)?(=)?Adverb===(=)?(=)?/g, '=== Hoker ===')
.replace(/===(=)?(=)?Verb===(=)?(=)?/g, '=== Lêker ===')
.replace(/===(=)?(=)?Noun===(=)?(=)?/g, '=== Navdêr ===')
.replace(/^==\s*([^=]+)\s*==$/g, '== {{ziman|{{subst:koda zimanî/en|$1}}}} ==')
.replace(/\{\{en-noun(.*?)/g, '{{en-navdêr$1')
.replace(/\{\{en-verb(.*?)/g, '{{en-lêker$1')
.replace(/\{\{en-adv(.*?)/g, '{{en-hoker$1')
.replace(/\{\{en-adj(.*?)/g, '{{en-rengdêr$1')
.replace(/\{\{en-proper noun(.*?)/g, '{{en-serenav$1')
.replace(/\{\{en-plural( |\-)noun\}\}/g, '{{navdêr|en|j=p}}')
.replace(/\{\{(pre|prefix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêş\|$2\|$3-\|$4\}\}\.')
.replace(/\{\{(suf|suffix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{paş\|$2\|$3\|-$4\}\}\.')
.replace(/\{\{(com|compound)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêk\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(con|confix)\|/g, 'Ji \{\{pêşûpaş|')
.replace(/\n# \{\{(alt|alternative) (spelling|form)( of)?\|/g, '# {{awayekî din|')
.replace(/\{\{(wp|wikipedia)\}\}/g, '{{wp|ziman=en}}')
.replace(/\{\{(pedia|pedialite)\}\}/g, '{{wpedî|ziman=en}}')
.replace(/\{\{(der|rel|col)\d\|/g, '{{kol3|')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol(2|3)\|en/g, '==== $1 ====\n{{kol$2|en|cure=$1')
.replace(/\n# \{\{infl of\|en\|(.*?)\|\|ing-form\}\}/g, '# {{partîsîpa niha|en|$1}}')
.replace(/\n# \{\{past participle of\|en\|(.*?)\|nocat=1\}\}/g, '# {{partîsîpa borî|en|$1}}')
.replace(/\n# \{\{en-past of\|/g, '# {{en-dema-borî|')
.replace(/\n# \{\{en-simple past of\|/g, '# {{en-dema-borî-sade|')
.replace(/\n# \{\{en-third-person singular of\|(.*?)\}\}/g, '# {{en-dema-niha|$1|sêyem|yekjimar}}')
.replace(/\n# \{\{plural of\|/g, '# {{pirjimar|')
.replace(/\n# \{\{en-superlative of\|/g, '# {{sûperlatîv|en|')
.replace(/\n# \{\{en-comparative of\|/g, '# {{komparatîv|en|')
.replace(/\n# \{\{(obs|obsolete|dated) (spelling|form)( of)\|/g, '# {{kevnbûyî|')
.replace(/\{\{bor\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{deyn|$2|$1$3')
.replace(/\{\{inh\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{mîr|$2|$1$3')
.replace(/\{\{u?der\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{ji|$2|$1$3')
.replace(/\{\{etyl\|(.*?)\|(.*?)\}\}/g, '{{ji|$1|$2|-}}')
.replace(/\{\{(cog|cognate)\|/g, '{{hv|')
.replace(/\{\{(noncognate|noncog|ncog|nc)\|/g, '{{nehevreh|')
.replace(/\{\{surf\|/g, '{{anlz|')
.replace(/\{\{desc\|/g, '{{dû|')
.replace(/\{\{desctree\|/g, '{{dardû|')
.replace(/bor=1/g, 'deyn=1')
.replace(/nocat=1/g, 'nekat=1')
.replace(/\|(t|gloss)([1-9][0-9]*)?=/g, '|w$2=')
.replace(/\|alt([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/\|head([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/bor=1/g, 'deyn=1')
.replace(/\[\[(Image|File):/g, '\[\[Wêne:')
.replace(/\*[ ]*?\[\[(.*)\]\]/g, '* {{g|en|$1}}')
.replace(/#\*[ ]*?'''([0-9]+)''' (.*?)\n#(\*)?:(.+)/g, '#* $4 {{jêder|$2, $1}}')
.replace(/=\nFrom/g, '=\nJi')
.replace(/}(,)? from {/g, '}, ji {')
.replace(/=\nBorrowed from/g, '=\nDeyn ji')
.replace(/(e|E)quivalent to( Ji)?/g, 'wekheva')
.replace(/}\.\.\n/g, '}.\n')
.replace(/\.[ ]*?wekheva/g, '. Wekheva')
.replace(/Ji Ji/g, 'Ji')
.replace(/<t:/g, '<w:')
.replace(/<g:/g, '<c:')
// jê bibe
.replace(/\{\{see desc\}\}/g, '')
.replace(/\n\* \{\{rhymes(.+)/g, '')
.replace(/\n\{\{was wotd(.+)/g, '')
.replace(/\n\{\{root\|(.+)(\n)?/g, '')
.replace(/{{enPR\|[^( |\n|,)]+/g, '')
.replace(/\|-}} {{qal\|([^\|]+)\|/g, '|')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:' + title + '|en.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'reformat',
forNamespaces: '0',
accessKey: 'q',
script: function(editor) {
editor
.replace(/\[\[([^\]]+)\]\]\s*(>|→)\s*\[\[([^\]]+)\]\]/g, '\n#: {{qfnim|ku|$1|$3}}')
.replace(/{{ji\|fr}} \[\[([^\]]+)\]\]/g, '{{deyn|fr|ku|$1}}')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[([^\]]+)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\-\]\] \+ \[\[([^\]]+)\]\](\.''|''\.|'')?/g, 'Ji {{navg|ku|$3|-$4-|$5}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\-\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêş|ku|$3-|$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{paş|ku|$3|-$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêk|ku|$3|$4}}.')
.replace(/\* Jihevqetandin: (.+)/g, '* {{ku-kîte}}')
.replace(/==== Ji wêjeyê ====([\s\S]*?)\((.*?)\)\n\n=/g, '==== Ji wêjeyê ====$1{{jêder|$2}}\n\n=')
.replace(/==== Ji wêjeyê ====\n(.+)\n\n{{jêder\|/g, '==== Ji wêjeyê ====\n\* $1 {{jêder|')
.replace(/===(=)?[ ]*?Bi soranî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|ckb}}:')
.replace(/===(=)?[ ]*?Bi zazakî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|zza}}:')
.replace(/''Bin(ê|e)re'': '''\[\[(.*?)\]\]'''/g, '{{guharto|ku|$2}}')
.replace(/fr(e|a)nsî \[\[([^\]]+)\]\](,)? ji latînî \[\[([^\]]+)\]\]/g, '{{ji|fr|ku|$2}}, ji {{ji|la|ku|$4}}')
.replace(/#[ ]*?\{\{bnr(2)?\|(.*?)\}\}(\n\n====[ ]*?Etîmolojî[ ]*?====)?/g, '# {{mane?|ku}}\n\n==== Etîmolojî ====')
.replace(/\{\{bnr(2)?\|(.*?)\}\}(\n\n\[\[Kategorî:Kurdî\]\])?/g, '\n# {{guharto|ku|$2}}')
.replace(/(îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî) \[\[([^\]]+)\]\]/g, '{{hv|{{subst:koda zimanî|$1}}|$2}}')
// .replace(/\[\[([^\]]+)\]\] ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$2}}|$1}}')
// .replace(/\[\[([^\]]+)\]\] \(([^\)]+)\) ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$3}}|$1|tr=$2}}')
.replace(/(avestayî|pehlewî|akadî) \'\'([^\']+)\'\'/g, '{{hv|{{subst:koda zimanî|$1}}||$2|sc=Latn}}')
.replace(/\|îbrî}}/g, '|îbranî}}')
.replace(/(soranî|farisî) {{g\|(ckb|fa)\|([^\}\}]+)}} \(([^\)]+)\)/g, '{{hv|$2|$3|tr=$4}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|ckb|$1|tr=$2}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|fa|$1|tr=$2}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|ckb|$1}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|fa|$1}}')
.replace(/\[\[hevreh\]\]a/g, 'hevreha')
.replace(/\[\[Şablon:(.*?)\|(.*?) (p|r)\.(.*?)\]\]/g, '\n* {{$1|r=$4}}')
.replace(/\[\[Şablon:(.*?)\]\]/g, '\n* {{$1}}')
.replace(/\*[ ]*?\[\[volapûkî\]\]/g, '* {{Z|vo}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\] \(([^\)]+)\)/g, '* {{Z|$1}}: {{W-|$1|$2|tr=$3}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\]/g, '* {{Z|$1}}: {{W-|$1|$2}}')
.replace(/'''(.*?)''':\n{{werger-ser}}/g, '{{werger-ser|$1}}')
.replace(/=== Bilêvkirin ===[ ]*?\n(\*\n[ ]*?)?\n/g, '')
.replace(/==== Bikaranîn ====\n{{\((\|vn=no)?}}/g, '==== Jê ====\n{{($1}}')
.replace(/==== Herwiha ====[ ]*?\n\*[ ]*?\n\n==== Jê ====[ ]*?\n\*[ ]*?\n\n==== Etîmolojî ====[ ]*?/g, '')
.replace(/\*[ ]*?{{ku-ar}}: {{ku-Arab\|\[\[(.*?)\]\]}}/g, '* {{ku-ar}}: {{g|ku|$1|sc=ku-Arab|tr=-}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3|$4}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1}}')
.replace(/\n#:[ ]*?{{hevmane\|ku\|(.*?)}}(,)?[ ]*?\n#:[ ]*?{{hevmane\|ku\|(.*?)}}/g, '\n#: {{hevmane|ku|$1|$3}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}$3\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*/g, '* {{mj|$1}}')
.replace(/\n\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[(.*)\]\]/g, '\n* {{mj|$1}} {{g|ku|$2}}')
.replace(/\n\*[ ]*?\[\[(.*)\]\]/g, '\n* {{g|ku|$1}}')
.replace(/\n(\*|#|#\*|#:)([^( |#\* |#: )])/g, '\n$1 $2')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/,/g, ', ')
.replace(/ ,/g, ',')
.replace(/ [ ]*?/g, ' ')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[z(e|i)lam\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|law}} e.')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[(keç|jin)\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|keç}} e.')
.replace(/(#)?\*?:?[ ]*?''(.*?)''[ ]*?{{jêder\|/g, '$1* {{jêder|ku|jêgirtin=$2|')
.replace(/jêgirtin= /g, 'jêgirtin=')
.replace(/'''[ ]*?Bi (zaravayên din|zazakî)[ ]*?'''/g, '==== Bi zaravayên din ====')
.replace(/Zazakî:/g, '* {{Z|zza}}:')
.replace(/{{navdêr\|ku\|c=-}}/g, '{{ku-tewîn-nav|{{subst:PAGENAME}}|-}}\n{{navdêr|ku|c=m}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin')
.clickDiff();
}
});
pathoschild.TemplateScript.add([
// add your own templates or scripts here
{
name: 'template n',
template: '=={{=nn|{{ucfirst:{{navê zimanî|' + modifiedTitle + '}}}}|' + modifiedTitle + '}}==<noinclude>[[Kategorî:Wîkîferheng:Sernavên zimanan]]</noinclude>',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:=nn|=nn]]}}',
forNamespaces: '10'
},
{
name: 'înterwîkî-çêke',
template: '{{subst:înterwîkî-çêke}}',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:înterwîkî-çêke|subst:înterwîkî-çêke]]}}',
forNamespaces: '14'
},
{
name: 'zimankatbike',
template: '{{zimankatbike|}}',
position: 'cursor',
accessKey: 'f',
forNamespaces: '14'
},
{
category: 'sererastkirin',
name: 'tewîn',
template: '{{ku-tewîn-nav|{{subst:PAGENAME}}|mê}}',
accessKey: '4',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'guharto',
template: '# {{guharto|}}',
position: 'cursor',
accessKey: '',
editSummary: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab|cure=navdêr|c=z|m=m|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab-lêker',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab-lêker|c=h-gh|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'rengdêr',
template: '{{subst:Bikarhêner:Wikihez/preload-rengdêr|ziman=ku|cure=rengdêr}}',
position: 'cursor',
accessKey: '2',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'gp',
template: '{{subst:Bikarhêner:Wikihez/preload-gp}}',
position: 'cursor',
editSummary: '',
forNamespaces: '0'
},
{
category: 'gotûbêj',
name: 'ragihandin',
template: ':{{r| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'outdent',
template: '{{outdent| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'ds',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=standardkirinê|2=DS|meh=Çîriya paşîn|dp=ds|peyitandî=standardkirin|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '1',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'dp',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=peyitandinê|2=DP|meh=Çîriya paşîn|dp=dp|peyitandî=peyitandî|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '2',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'arşîvbin',
template: '{{arşîv-bin}}',
position: 'cursor',
editSummary: 'a',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'xêrhatin',
template: '{{subst:şablon:bixêrhatin/preload}}',
position: 'cursor',
editSummary: 'xêrhatin lê zêde kir',
forNamespaces: 'user talk'
},
{
name: 'nepeyitandî',
template: ':{{nepeyitandî}}--~~~~',
position: 'after',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +{{[[şablon:nepeyitandî|nepeyitandî]]}}',
forNamespaces: '4',
script: function(editor) {
editor
.replace(/== \[\[(.*?)\]\] ==/g, '== <s>\[\[$1\]\]</s> ==');
}
},
{
name: 'jinûvesazî',
template: '{{subst:Bikarhêner:Wikihez/jinûvesazî|ziman=ine-pro|cure=navdêr|peyv= }}',
position: 'cursor',
editSummary: '',
accessKey: '1',
forNamespaces: '108'
},
]);
});
// </nowiki>
nbg4jrvcc7m086s6yuw9vz2nnyeipyv
6241924
6241923
2026-07-12T22:45:16Z
Wikihez
7344
6241924
javascript
text/javascript
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
var title = mw.config.get('wgTitle');
// Remove '=' from the title using the replace method
var modifiedTitle = title.replace(/=/g, '');
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
pathoschild.TemplateScript.add({
name:'kolon',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/{{\)}}/g, '}}')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '|$2<q:$1>')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$3<q:$1>')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$2')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '|$1')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'nimûne',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/#:\s*'{2}(.*?)'{2}\n/g, '#: {{nm|tr|$1|rêz=1}}\n')
.replace(/#:\s*'{2}(.*?)'{2}\s*\(([^\)]+)\)\.?\n/g, '#: {{nm|tr|$1|$2|rêz=1}}\n')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Formata [[Şablon:nimûne|nimûneyan]]+')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'parentez bike îzah',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\(([^\)]+)\)/g, '{{îzah|$1}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'bnr bike ku-Latn',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr(2)?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=-}}\n# {{ku-Latn|$2}}\n\n==== Bi alfabeyên din ====\n* {{ku-ar|' + title + '}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: [[Şablon:ku-Latn|{{ku-Latn}}]]+')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'herwiha',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$2||$1}}')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '| {{hw|ku|$2}}')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$1}}')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'ji dewikt',
// forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{Worttrennung\}\}\n:([\w·]+),\s*\{\{Pl\.\}\}\s*([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}} {{Pl.}} {{kîte|de|$2|nivîs=na}}')
.replace(/\{\{Worttrennung\}\}\n:([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}}')
.replace(/·/g, '|')
.replace(/\s*\{\{Aussprache}}\s*/g, '\n')
.replace(/:\{\{IPA\}\}\s*\{\{Lautschrift\|([^\}]+)\}\}/g, '* {{IPA|de|[$1]}}')
.replace(/:\{\{Hörbeispiele\}\}\s*\{\{Audio\|([^\}]+)\}\}/g, '* {{deng|de|$1}}')
.replace(/,?\s*\{\{Audio\|([^\|]+)\|spr=at}}/g, '\n* {{deng|de|$1|dever=Awistirya}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[de:' + title + '|de.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'bnr û beralîkirin bike guharto',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr2?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=}}\n# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}')
.replace(/#B?E?R?A?L?Î?K?I?R?I?N? \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
// .replace(/# \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
}
});
pathoschild.TemplateScript.add({
name:'bikeKurdî',
accessKey: 'a',
script: function(editor) {
editor
.replace(/Central Iranian:/g, 'Îraniya merkezî')
.replace(/Northeastern Iranian:/g, 'Îraniya bakurêrojhilatî:')
.replace(/Southeastern Iranian:/g, 'Îraniya başûrêrojhilatî:')
.replace(/Northwestern Iranian:/g, 'Îraniya bakurêrojavayî:')
.replace(/Southwestern Iranian:/g, 'Îraniya başûrêrojavayî:')
.replace(/Munji-Yidgha:/g, 'Munjî-Yidghayî:')
.replace(/Kurdish:/g, 'Kurdî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Mazanderani-Shahmirzadi:/g, 'Mazenderanî-Şahmîrzadî:')
.replace(/Medo-Parthian:/g, 'Medo-partî:')
.replace(/\|kmr(\||\})/g, '|ku$1')
.replace(/\|g(\d+)?=m(\||\})/g, '|c$1=n$2')
.replace(/\|g(\d+)?=f(\||\})/g, '|c$1=m$2')
.replace(/\|g(\d+)?=n(\||\})/g, '|c$1=nt$2')
.replace(/\{\{(a|qualifier|qual|q)\|/g, '{{mj|')
.replace(/\{\{(s|sense)\|/g, '{{mane|')
.replace(/\{\{(af|affix)\|/g, '{{qertaf|')
.replace(/\{\{anagrams\|/g, '{{anagram|')
.replace(/\{\{also\|/g, '{{bnr-h|')
.replace(/\{\{(homophones|homophone|hmp)\|/g, '{{hevdeng|')
.replace(/\{\{(dbt|doublet)\|/g, '{{cotreh|')
.replace(/\{\{alter\|/g, '{{hw|')
.replace(/\{\{alt\|/g, '{{hw|')
.replace(/\{\{(synonyms|syn)\|/g, '{{hevmane|')
.replace(/\{\{(antonyms|antonym|ant)\|/g, '{{dijmane|')
.replace(/\{\{(hyponyms|hypo)\|/g, '{{jêrnav|')
.replace(/\{\{(hypernyms|hyper)\|/g, '{{jornav|')
.replace(/\{\{(coordinate terms|cot)\|/g, '{{koordîne|')
.replace(/\{\{(inline alt forms|alti)\|/g, '{{herwiha-rêz|')
.replace(/\{\{(hyphenation|hyph)\|/g, '{{kîte|')
.replace(/\{\{(back-form|back-formation|bf)\|/g, '{{paşvesazî|')
.replace(/\{\{l\|/g, '{{g|')
.replace(/\{\{m\|/g, '{{qal|')
.replace(/\{\{(label|lb)\|/g, '{{e|')
.replace(/\|(UK|RP)(\||\}\})/g, '|QY$2')
.replace(/\|AU(\||\}\})/g, '|Awistralya$1')
.replace(/\|Australia(\||\}\})/g, '|Awistralya$1')
.replace(/\|mul(\||\}\})/g, '|navz$1')
.replace(/\|Canada(\||\}\})/g, '|Kanada$1')
.replace(/\|informal(\||\}\})/g, '|neresmî$1')
.replace(/\|rare(\||\}\})/g, '|kêmpeyda$1')
.replace(/\|archaic(\||\}\})/g, '|kevnare$1')
.replace(/\|slang(\||\}\})/g, '|argo$1')
.replace(/\|idiomatic(\||\}\})/g, '|biwêjî$1')
.replace(/\|obsolete(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|dated(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|(US|USA|GenAm|GA)(\||\}\})/g, '\|DYA$2')
.replace(/\{\{audio\|/g, '{{deng|')
.replace(/\|[ ]*a[ ]*=[ ]*(US|USA|GA|GenAm)/g, '|dever=DYA')
.replace(/\|[ ]*a[ ]*=[ ]*Southern England/g, '|dever=Îngilistana başûr')
.replace(/\|[ ]*a[ ]*=[ ]*(UK|RP)/g, '|dever=QY')
.replace(/\|[ ]*a[ ]*=[ ]*AU/g, '|dever=Awistralya')
.replace(/[aA]udio \((UK|RP)\)/g, 'Deng (QY\)')
.replace(/\|[aA]udio \(Southern England\)\}\}/g, '\|Deng \(Îngilistana başûr\)}\}')
.replace(/[aA]udio \(AU\)/g, 'Deng \(Awistralya\)')
.replace(/[aA]udio \((US|USA|GA|GenAm)\)/g, 'Deng \(DYA\)')
.replace(/===(=)?(=)?Verb===(=)?(=)?\n{{head\|en\|verb form}}/g, '=== Formeke lêkerê ===\n{{lêker|en|form=erê}}')
.replace(/===(=)?(=)?Noun===(=)?(=)?\n{{head\|en\|noun form}}/g, '=== Formeke navdêrê ===\n{{navdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adjective===(=)?(=)?\n{{head\|en\|(comparative|superlative) adjective}}/g, '=== Formeke rengdêrê ===\n{{rengdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adverb===(=)?(=)?\n{{head\|en\|(comparative|superlative) adverb}}/g, '=== Formeke hokerê ===\n{{hoker|en|form=erê}}')
.replace(/===(=)?(=)?Synonyms===(=)?(=)?/g, '==== Hevmane ====')
.replace(/===(=)?(=)?Coordinate terms===(=)?(=)?/g, '==== Termên koordîne ====')
.replace(/===(=)?(=)?Antonyms===(=)?(=)?/g, '==== Dijmane ====')
.replace(/===(=)?(=)?Descendants===(=)?(=)?/g, '==== Dûnde ====')
.replace(/===(=)?(=)?Derived terms===(=)?(=)?/g, '==== Jê ====')
.replace(/===(=)?(=)?Alternative forms===(=)?(=)?/g, '==== Herwiha ====')
.replace(/===(=)?(=)?Related terms===(=)?(=)?/g, '==== Têkildar ====')
.replace(/===(=)?(=)?See also===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Anagrams===(=)?(=)?/g, '==== Anagram ====')
.replace(/===(=)?(=)?Further reading===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Pronunciation(.*?)===(=)?(=)?/g, '=== Bilêvkirin ===')
.replace(/===(=)?(=)?Etymology(.*?)===(=)?(=)?/g, '==== Etîmolojî ====')
.replace(/===(=)?(=)?Hyponyms===(=)?(=)?/g, '==== Jêrnav ====')
.replace(/===(=)?(=)?Hypernyms===(=)?(=)?/g, '==== Jornav ====')
.replace(/===(=)?(=)?Proper (n|N)oun===(=)?(=)?/g, '=== Serenav ===')
.replace(/===(=)?(=)?Adjective===(=)?(=)?/g, '=== Rengdêr ===')
.replace(/===(=)?(=)?Adverb===(=)?(=)?/g, '=== Hoker ===')
.replace(/===(=)?(=)?Verb===(=)?(=)?/g, '=== Lêker ===')
.replace(/===(=)?(=)?Noun===(=)?(=)?/g, '=== Navdêr ===')
.replace(/^==\s*([^=]+)\s*==$/, '== {{ziman|{{subst:en-to-kod|$1}}}} ==')
.replace(/\{\{en-noun(.*?)/g, '{{en-navdêr$1')
.replace(/\{\{en-verb(.*?)/g, '{{en-lêker$1')
.replace(/\{\{en-adv(.*?)/g, '{{en-hoker$1')
.replace(/\{\{en-adj(.*?)/g, '{{en-rengdêr$1')
.replace(/\{\{en-proper noun(.*?)/g, '{{en-serenav$1')
.replace(/\{\{en-plural( |\-)noun\}\}/g, '{{navdêr|en|j=p}}')
.replace(/\{\{(pre|prefix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêş\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(suf|suffix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{paş\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(com|compound)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêk\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(con|confix)\|/g, 'Ji \{\{pêşûpaş|')
.replace(/\n# \{\{(alt|alternative) (spelling|form)( of)?\|/g, '# {{awayekî din|')
.replace(/\{\{(wp|wikipedia)\}\}/g, '{{wp|ziman=en}}')
.replace(/\{\{(pedia|pedialite)\}\}/g, '{{wpedî|ziman=en}}')
.replace(/\{\{(der|rel|col)\d\|/g, '{{kol3|')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol(2|3)\|en/g, '==== $1 ====\n{{kol$2|en|cure=$1')
.replace(/\n# \{\{infl of\|en\|(.*?)\|\|ing-form\}\}/g, '# {{partîsîpa niha|en|$1}}')
.replace(/\n# \{\{past participle of\|en\|(.*?)\|nocat=1\}\}/g, '# {{partîsîpa borî|en|$1}}')
.replace(/\n# \{\{en-past of\|/g, '# {{en-dema-borî|')
.replace(/\n# \{\{en-simple past of\|/g, '# {{en-dema-borî-sade|')
.replace(/\n# \{\{en-third-person singular of\|(.*?)\}\}/g, '# {{en-dema-niha|$1|sêyem|yekjimar}}')
.replace(/\n# \{\{plural of\|/g, '# {{pirjimar|')
.replace(/\n# \{\{en-superlative of\|/g, '# {{sûperlatîv|en|')
.replace(/\n# \{\{en-comparative of\|/g, '# {{komparatîv|en|')
.replace(/\n# \{\{(obs|obsolete|dated) (spelling|form)( of)\|/g, '# {{kevnbûyî|')
.replace(/\{\{bor\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{deyn|$2|$1$3')
.replace(/\{\{inh\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{mîr|$2|$1$3')
.replace(/\{\{u?der\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{ji|$2|$1$3')
.replace(/\{\{etyl\|(.*?)\|(.*?)\}\}/g, '{{ji|$1|$2|-}}')
.replace(/\{\{(cog|cognate)\|/g, '{{hv|')
.replace(/\{\{(noncognate|noncog|ncog|nc)\|/g, '{{nh|')
.replace(/\{\{surf\|/g, '{{anlz|')
.replace(/\{\{desc\|/g, '{{dû|')
.replace(/\{\{desctree\|/g, '{{dardû|')
.replace(/bor=1/g, 'deyn=1')
.replace(/nocat=1/g, 'nekat=1')
.replace(/\|(t|gloss)([1-9][0-9]*)?=/g, '|w$2=')
.replace(/\|alt([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/\|head([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/bor=1/g, 'deyn=1')
.replace(/\[\[(Image|File):/g, '\[\[Wêne:')
.replace(/\*[ ]*?\[\[(.*)\]\]/g, '* {{g|en|$1}}')
.replace(/#\*[ ]*?'''([0-9]+)''' (.*?)\n#(\*)?:(.+)/g, '#* $4 {{jêder|$2, $1}}')
.replace(/=\nFrom/g, '=\nJi')
.replace(/}(,)? from {/g, '}, ji {')
.replace(/=\nBorrowed from/g, '=\nDeyn ji')
.replace(/(e|E)quivalent to( Ji)?/g, 'wekheva')
.replace(/}\.\.\n/g, '}.\n')
.replace(/\.[ ]*?wekheva/g, '. Wekheva')
.replace(/Ji Ji/g, 'Ji')
.replace(/<t:/g, '<w:')
.replace(/<g:/g, '<c:')
// jê bibe
.replace(/\{\{see desc\}\}/g, '')
.replace(/\n\* \{\{rhymes(.+)/g, '')
.replace(/\n\{\{was wotd(.+)/g, '')
.replace(/\n\{\{root\|(.+)(\n)?/g, '')
.replace(/{{enPR\|[^( |\n|,)]+/g, '')
.replace(/\|-}} {{qal\|([^\|]+)\|/g, '|')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:' + title + '|en.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'reformat',
forNamespaces: '0',
accessKey: 'q',
script: function(editor) {
editor
.replace(/\[\[([^\]]+)\]\]\s*(>|→)\s*\[\[([^\]]+)\]\]/g, '\n#: {{qfnim|ku|$1|$3}}')
.replace(/{{ji\|fr}} \[\[([^\]]+)\]\]/g, '{{deyn|fr|ku|$1}}')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[([^\]]+)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\-\]\] \+ \[\[([^\]]+)\]\](\.''|''\.|'')?/g, 'Ji {{navg|ku|$3|-$4-|$5}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\-\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêş|ku|$3-|$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{paş|ku|$3|-$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêk|ku|$3|$4}}.')
.replace(/\* Jihevqetandin: (.+)/g, '* {{ku-kîte}}')
.replace(/==== Ji wêjeyê ====([\s\S]*?)\((.*?)\)\n\n=/g, '==== Ji wêjeyê ====$1{{jêder|$2}}\n\n=')
.replace(/==== Ji wêjeyê ====\n(.+)\n\n{{jêder\|/g, '==== Ji wêjeyê ====\n\* $1 {{jêder|')
.replace(/===(=)?[ ]*?Bi soranî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|ckb}}:')
.replace(/===(=)?[ ]*?Bi zazakî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|zza}}:')
.replace(/''Bin(ê|e)re'': '''\[\[(.*?)\]\]'''/g, '{{guharto|ku|$2}}')
.replace(/fr(e|a)nsî \[\[([^\]]+)\]\](,)? ji latînî \[\[([^\]]+)\]\]/g, '{{ji|fr|ku|$2}}, ji {{ji|la|ku|$4}}')
.replace(/#[ ]*?\{\{bnr(2)?\|(.*?)\}\}(\n\n====[ ]*?Etîmolojî[ ]*?====)?/g, '# {{mane?|ku}}\n\n==== Etîmolojî ====')
.replace(/\{\{bnr(2)?\|(.*?)\}\}(\n\n\[\[Kategorî:Kurdî\]\])?/g, '\n# {{guharto|ku|$2}}')
.replace(/(îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî) \[\[([^\]]+)\]\]/g, '{{hv|{{subst:koda zimanî|$1}}|$2}}')
// .replace(/\[\[([^\]]+)\]\] ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$2}}|$1}}')
// .replace(/\[\[([^\]]+)\]\] \(([^\)]+)\) ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$3}}|$1|tr=$2}}')
.replace(/(avestayî|pehlewî|akadî) \'\'([^\']+)\'\'/g, '{{hv|{{subst:koda zimanî|$1}}||$2|sc=Latn}}')
.replace(/\|îbrî}}/g, '|îbranî}}')
.replace(/(soranî|farisî) {{g\|(ckb|fa)\|([^\}\}]+)}} \(([^\)]+)\)/g, '{{hv|$2|$3|tr=$4}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|ckb|$1|tr=$2}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|fa|$1|tr=$2}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|ckb|$1}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|fa|$1}}')
.replace(/\[\[hevreh\]\]a/g, 'hevreha')
.replace(/\[\[Şablon:(.*?)\|(.*?) (p|r)\.(.*?)\]\]/g, '\n* {{$1|r=$4}}')
.replace(/\[\[Şablon:(.*?)\]\]/g, '\n* {{$1}}')
.replace(/\*[ ]*?\[\[volapûkî\]\]/g, '* {{Z|vo}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\] \(([^\)]+)\)/g, '* {{Z|$1}}: {{W-|$1|$2|tr=$3}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\]/g, '* {{Z|$1}}: {{W-|$1|$2}}')
.replace(/'''(.*?)''':\n{{werger-ser}}/g, '{{werger-ser|$1}}')
.replace(/=== Bilêvkirin ===[ ]*?\n(\*\n[ ]*?)?\n/g, '')
.replace(/==== Bikaranîn ====\n{{\((\|vn=no)?}}/g, '==== Jê ====\n{{($1}}')
.replace(/==== Herwiha ====[ ]*?\n\*[ ]*?\n\n==== Jê ====[ ]*?\n\*[ ]*?\n\n==== Etîmolojî ====[ ]*?/g, '')
.replace(/\*[ ]*?{{ku-ar}}: {{ku-Arab\|\[\[(.*?)\]\]}}/g, '* {{ku-ar}}: {{g|ku|$1|sc=ku-Arab|tr=-}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3|$4}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1}}')
.replace(/\n#:[ ]*?{{hevmane\|ku\|(.*?)}}(,)?[ ]*?\n#:[ ]*?{{hevmane\|ku\|(.*?)}}/g, '\n#: {{hevmane|ku|$1|$3}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}$3\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*/g, '* {{mj|$1}}')
.replace(/\n\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[(.*)\]\]/g, '\n* {{mj|$1}} {{g|ku|$2}}')
.replace(/\n\*[ ]*?\[\[(.*)\]\]/g, '\n* {{g|ku|$1}}')
.replace(/\n(\*|#|#\*|#:)([^( |#\* |#: )])/g, '\n$1 $2')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/,/g, ', ')
.replace(/ ,/g, ',')
.replace(/ [ ]*?/g, ' ')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[z(e|i)lam\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|law}} e.')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[(keç|jin)\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|keç}} e.')
.replace(/(#)?\*?:?[ ]*?''(.*?)''[ ]*?{{jêder\|/g, '$1* {{jêder|ku|jêgirtin=$2|')
.replace(/jêgirtin= /g, 'jêgirtin=')
.replace(/'''[ ]*?Bi (zaravayên din|zazakî)[ ]*?'''/g, '==== Bi zaravayên din ====')
.replace(/Zazakî:/g, '* {{Z|zza}}:')
.replace(/{{navdêr\|ku\|c=-}}/g, '{{ku-tewîn-nav|{{subst:PAGENAME}}|-}}\n{{navdêr|ku|c=m}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin')
.clickDiff();
}
});
pathoschild.TemplateScript.add([
// add your own templates or scripts here
{
name: 'template n',
template: '=={{=nn|{{ucfirst:{{navê zimanî|' + modifiedTitle + '}}}}|' + modifiedTitle + '}}==<noinclude>[[Kategorî:Wîkîferheng:Sernavên zimanan]]</noinclude>',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:=nn|=nn]]}}',
forNamespaces: '10'
},
{
name: 'înterwîkî-çêke',
template: '{{subst:înterwîkî-çêke}}',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:înterwîkî-çêke|subst:înterwîkî-çêke]]}}',
forNamespaces: '14'
},
{
name: 'zimankatbike',
template: '{{zimankatbike|}}',
position: 'cursor',
accessKey: 'f',
forNamespaces: '14'
},
{
category: 'sererastkirin',
name: 'tewîn',
template: '{{ku-tewîn-nav|{{subst:PAGENAME}}|mê}}',
accessKey: '4',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'guharto',
template: '# {{guharto|}}',
position: 'cursor',
accessKey: '',
editSummary: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab|cure=navdêr|c=z|m=m|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab-lêker',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab-lêker|c=h-gh|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'rengdêr',
template: '{{subst:Bikarhêner:Wikihez/preload-rengdêr|ziman=ku|cure=rengdêr}}',
position: 'cursor',
accessKey: '2',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'gp',
template: '{{subst:Bikarhêner:Wikihez/preload-gp}}',
position: 'cursor',
editSummary: '',
forNamespaces: '0'
},
{
category: 'gotûbêj',
name: 'ragihandin',
template: ':{{r| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'outdent',
template: '{{outdent| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'ds',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=standardkirinê|2=DS|meh=Çîriya paşîn|dp=ds|peyitandî=standardkirin|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '1',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'dp',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=peyitandinê|2=DP|meh=Çîriya paşîn|dp=dp|peyitandî=peyitandî|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '2',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'arşîvbin',
template: '{{arşîv-bin}}',
position: 'cursor',
editSummary: 'a',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'xêrhatin',
template: '{{subst:şablon:bixêrhatin/preload}}',
position: 'cursor',
editSummary: 'xêrhatin lê zêde kir',
forNamespaces: 'user talk'
},
{
name: 'nepeyitandî',
template: ':{{nepeyitandî}}--~~~~',
position: 'after',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +{{[[şablon:nepeyitandî|nepeyitandî]]}}',
forNamespaces: '4',
script: function(editor) {
editor
.replace(/== \[\[(.*?)\]\] ==/g, '== <s>\[\[$1\]\]</s> ==');
}
},
{
name: 'jinûvesazî',
template: '{{subst:Bikarhêner:Wikihez/jinûvesazî|ziman=ine-pro|cure=navdêr|peyv= }}',
position: 'cursor',
editSummary: '',
accessKey: '1',
forNamespaces: '108'
},
]);
});
// </nowiki>
trj49f4vsu1apq538t7dsufzq1dn493
6241925
6241924
2026-07-12T22:47:55Z
Wikihez
7344
6241925
javascript
text/javascript
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
var title = mw.config.get('wgTitle');
// Remove '=' from the title using the replace method
var modifiedTitle = title.replace(/=/g, '');
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
pathoschild.TemplateScript.add({
name:'kolon',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/{{\)}}/g, '}}')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '|$2<q:$1>')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$3<q:$1>')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$2')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '|$1')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'nimûne',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/#:\s*'{2}(.*?)'{2}\n/g, '#: {{nm|tr|$1|rêz=1}}\n')
.replace(/#:\s*'{2}(.*?)'{2}\s*\(([^\)]+)\)\.?\n/g, '#: {{nm|tr|$1|$2|rêz=1}}\n')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Formata [[Şablon:nimûne|nimûneyan]]+')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'parentez bike îzah',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\(([^\)]+)\)/g, '{{îzah|$1}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'bnr bike ku-Latn',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr(2)?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=-}}\n# {{ku-Latn|$2}}\n\n==== Bi alfabeyên din ====\n* {{ku-ar|' + title + '}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: [[Şablon:ku-Latn|{{ku-Latn}}]]+')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'herwiha',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$2||$1}}')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '| {{hw|ku|$2}}')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$1}}')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'ji dewikt',
// forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{Worttrennung\}\}\n:([\w·]+),\s*\{\{Pl\.\}\}\s*([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}} {{Pl.}} {{kîte|de|$2|nivîs=na}}')
.replace(/\{\{Worttrennung\}\}\n:([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}}')
.replace(/·/g, '|')
.replace(/\s*\{\{Aussprache}}\s*/g, '\n')
.replace(/:\{\{IPA\}\}\s*\{\{Lautschrift\|([^\}]+)\}\}/g, '* {{IPA|de|[$1]}}')
.replace(/:\{\{Hörbeispiele\}\}\s*\{\{Audio\|([^\}]+)\}\}/g, '* {{deng|de|$1}}')
.replace(/,?\s*\{\{Audio\|([^\|]+)\|spr=at}}/g, '\n* {{deng|de|$1|dever=Awistirya}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[de:' + title + '|de.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'bnr û beralîkirin bike guharto',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr2?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=}}\n# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}')
.replace(/#B?E?R?A?L?Î?K?I?R?I?N? \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
// .replace(/# \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
}
});
pathoschild.TemplateScript.add({
name:'bikeKurdî',
accessKey: 'a',
script: function(editor) {
editor
.replace(/Central Iranian:/g, 'Îraniya merkezî')
.replace(/Northeastern Iranian:/g, 'Îraniya bakurêrojhilatî:')
.replace(/Southeastern Iranian:/g, 'Îraniya başûrêrojhilatî:')
.replace(/Northwestern Iranian:/g, 'Îraniya bakurêrojavayî:')
.replace(/Southwestern Iranian:/g, 'Îraniya başûrêrojavayî:')
.replace(/Munji-Yidgha:/g, 'Munjî-Yidghayî:')
.replace(/Kurdish:/g, 'Kurdî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Mazanderani-Shahmirzadi:/g, 'Mazenderanî-Şahmîrzadî:')
.replace(/Medo-Parthian:/g, 'Medo-partî:')
.replace(/\|kmr(\||\})/g, '|ku$1')
.replace(/\|g(\d+)?=m(\||\})/g, '|c$1=n$2')
.replace(/\|g(\d+)?=f(\||\})/g, '|c$1=m$2')
.replace(/\|g(\d+)?=n(\||\})/g, '|c$1=nt$2')
.replace(/\{\{(a|qualifier|qual|q)\|/g, '{{mj|')
.replace(/\{\{(s|sense)\|/g, '{{mane|')
.replace(/\{\{(af|affix)\|/g, '{{qertaf|')
.replace(/\{\{anagrams\|/g, '{{anagram|')
.replace(/\{\{also\|/g, '{{bnr-h|')
.replace(/\{\{(homophones|homophone|hmp)\|/g, '{{hevdeng|')
.replace(/\{\{(dbt|doublet)\|/g, '{{cotreh|')
.replace(/\{\{alter\|/g, '{{hw|')
.replace(/\{\{alt\|/g, '{{hw|')
.replace(/\{\{(synonyms|syn)\|/g, '{{hevmane|')
.replace(/\{\{(antonyms|antonym|ant)\|/g, '{{dijmane|')
.replace(/\{\{(hyponyms|hypo)\|/g, '{{jêrnav|')
.replace(/\{\{(hypernyms|hyper)\|/g, '{{jornav|')
.replace(/\{\{(coordinate terms|cot)\|/g, '{{koordîne|')
.replace(/\{\{(inline alt forms|alti)\|/g, '{{herwiha-rêz|')
.replace(/\{\{(hyphenation|hyph)\|/g, '{{kîte|')
.replace(/\{\{(back-form|back-formation|bf)\|/g, '{{paşvesazî|')
.replace(/\{\{l\|/g, '{{g|')
.replace(/\{\{m\|/g, '{{qal|')
.replace(/\{\{(label|lb)\|/g, '{{e|')
.replace(/\|(UK|RP)(\||\}\})/g, '|QY$2')
.replace(/\|AU(\||\}\})/g, '|Awistralya$1')
.replace(/\|Australia(\||\}\})/g, '|Awistralya$1')
.replace(/\|mul(\||\}\})/g, '|navz$1')
.replace(/\|Canada(\||\}\})/g, '|Kanada$1')
.replace(/\|informal(\||\}\})/g, '|neresmî$1')
.replace(/\|rare(\||\}\})/g, '|kêmpeyda$1')
.replace(/\|archaic(\||\}\})/g, '|kevnare$1')
.replace(/\|slang(\||\}\})/g, '|argo$1')
.replace(/\|idiomatic(\||\}\})/g, '|biwêjî$1')
.replace(/\|obsolete(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|dated(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|(US|USA|GenAm|GA)(\||\}\})/g, '\|DYA$2')
.replace(/\{\{audio\|/g, '{{deng|')
.replace(/\|[ ]*a[ ]*=[ ]*(US|USA|GA|GenAm)/g, '|dever=DYA')
.replace(/\|[ ]*a[ ]*=[ ]*Southern England/g, '|dever=Îngilistana başûr')
.replace(/\|[ ]*a[ ]*=[ ]*(UK|RP)/g, '|dever=QY')
.replace(/\|[ ]*a[ ]*=[ ]*AU/g, '|dever=Awistralya')
.replace(/[aA]udio \((UK|RP)\)/g, 'Deng (QY\)')
.replace(/\|[aA]udio \(Southern England\)\}\}/g, '\|Deng \(Îngilistana başûr\)}\}')
.replace(/[aA]udio \(AU\)/g, 'Deng \(Awistralya\)')
.replace(/[aA]udio \((US|USA|GA|GenAm)\)/g, 'Deng \(DYA\)')
.replace(/===(=)?(=)?Verb===(=)?(=)?\n{{head\|en\|verb form}}/g, '=== Formeke lêkerê ===\n{{lêker|en|form=erê}}')
.replace(/===(=)?(=)?Noun===(=)?(=)?\n{{head\|en\|noun form}}/g, '=== Formeke navdêrê ===\n{{navdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adjective===(=)?(=)?\n{{head\|en\|(comparative|superlative) adjective}}/g, '=== Formeke rengdêrê ===\n{{rengdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adverb===(=)?(=)?\n{{head\|en\|(comparative|superlative) adverb}}/g, '=== Formeke hokerê ===\n{{hoker|en|form=erê}}')
.replace(/===(=)?(=)?Synonyms===(=)?(=)?/g, '==== Hevmane ====')
.replace(/===(=)?(=)?Coordinate terms===(=)?(=)?/g, '==== Termên koordîne ====')
.replace(/===(=)?(=)?Antonyms===(=)?(=)?/g, '==== Dijmane ====')
.replace(/===(=)?(=)?Descendants===(=)?(=)?/g, '==== Dûnde ====')
.replace(/===(=)?(=)?Derived terms===(=)?(=)?/g, '==== Jê ====')
.replace(/===(=)?(=)?Alternative forms===(=)?(=)?/g, '==== Herwiha ====')
.replace(/===(=)?(=)?Related terms===(=)?(=)?/g, '==== Têkildar ====')
.replace(/===(=)?(=)?See also===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Anagrams===(=)?(=)?/g, '==== Anagram ====')
.replace(/===(=)?(=)?Further reading===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Pronunciation(.*?)===(=)?(=)?/g, '=== Bilêvkirin ===')
.replace(/===(=)?(=)?Etymology(.*?)===(=)?(=)?/g, '==== Etîmolojî ====')
.replace(/===(=)?(=)?Hyponyms===(=)?(=)?/g, '==== Jêrnav ====')
.replace(/===(=)?(=)?Hypernyms===(=)?(=)?/g, '==== Jornav ====')
.replace(/===(=)?(=)?Proper (n|N)oun===(=)?(=)?/g, '=== Serenav ===')
.replace(/===(=)?(=)?Adjective===(=)?(=)?/g, '=== Rengdêr ===')
.replace(/===(=)?(=)?Adverb===(=)?(=)?/g, '=== Hoker ===')
.replace(/===(=)?(=)?Verb===(=)?(=)?/g, '=== Lêker ===')
.replace(/===(=)?(=)?Noun===(=)?(=)?/g, '=== Navdêr ===')
.replace(/^==([^=]+)==$/g, '== {{ziman|{{subst:en-to-kod|$1}}}} ==')
.replace(/\{\{en-noun(.*?)/g, '{{en-navdêr$1')
.replace(/\{\{en-verb(.*?)/g, '{{en-lêker$1')
.replace(/\{\{en-adv(.*?)/g, '{{en-hoker$1')
.replace(/\{\{en-adj(.*?)/g, '{{en-rengdêr$1')
.replace(/\{\{en-proper noun(.*?)/g, '{{en-serenav$1')
.replace(/\{\{en-plural( |\-)noun\}\}/g, '{{navdêr|en|j=p}}')
.replace(/\{\{(pre|prefix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêş\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(suf|suffix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{paş\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(com|compound)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêk\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(con|confix)\|/g, 'Ji \{\{pêşûpaş|')
.replace(/\n# \{\{(alt|alternative) (spelling|form)( of)?\|/g, '# {{awayekî din|')
.replace(/\{\{(wp|wikipedia)\}\}/g, '{{wp|ziman=en}}')
.replace(/\{\{(pedia|pedialite)\}\}/g, '{{wpedî|ziman=en}}')
.replace(/\{\{(der|rel|col)\d\|/g, '{{kol3|')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol(2|3)\|en/g, '==== $1 ====\n{{kol$2|en|cure=$1')
.replace(/\n# \{\{infl of\|en\|(.*?)\|\|ing-form\}\}/g, '# {{partîsîpa niha|en|$1}}')
.replace(/\n# \{\{past participle of\|en\|(.*?)\|nocat=1\}\}/g, '# {{partîsîpa borî|en|$1}}')
.replace(/\n# \{\{en-past of\|/g, '# {{en-dema-borî|')
.replace(/\n# \{\{en-simple past of\|/g, '# {{en-dema-borî-sade|')
.replace(/\n# \{\{en-third-person singular of\|(.*?)\}\}/g, '# {{en-dema-niha|$1|sêyem|yekjimar}}')
.replace(/\n# \{\{plural of\|/g, '# {{pirjimar|')
.replace(/\n# \{\{en-superlative of\|/g, '# {{sûperlatîv|en|')
.replace(/\n# \{\{en-comparative of\|/g, '# {{komparatîv|en|')
.replace(/\n# \{\{(obs|obsolete|dated) (spelling|form)( of)\|/g, '# {{kevnbûyî|')
.replace(/\{\{bor\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{deyn|$2|$1$3')
.replace(/\{\{inh\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{mîr|$2|$1$3')
.replace(/\{\{u?der\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{ji|$2|$1$3')
.replace(/\{\{etyl\|(.*?)\|(.*?)\}\}/g, '{{ji|$1|$2|-}}')
.replace(/\{\{(cog|cognate)\|/g, '{{hv|')
.replace(/\{\{(noncognate|noncog|ncog|nc)\|/g, '{{nh|')
.replace(/\{\{surf\|/g, '{{anlz|')
.replace(/\{\{desc\|/g, '{{dû|')
.replace(/\{\{desctree\|/g, '{{dardû|')
.replace(/bor=1/g, 'deyn=1')
.replace(/nocat=1/g, 'nekat=1')
.replace(/\|(t|gloss)([1-9][0-9]*)?=/g, '|w$2=')
.replace(/\|alt([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/\|head([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/bor=1/g, 'deyn=1')
.replace(/\[\[(Image|File):/g, '\[\[Wêne:')
.replace(/\*[ ]*?\[\[(.*)\]\]/g, '* {{g|en|$1}}')
.replace(/#\*[ ]*?'''([0-9]+)''' (.*?)\n#(\*)?:(.+)/g, '#* $4 {{jêder|$2, $1}}')
.replace(/=\nFrom/g, '=\nJi')
.replace(/}(,)? from {/g, '}, ji {')
.replace(/=\nBorrowed from/g, '=\nDeyn ji')
.replace(/(e|E)quivalent to( Ji)?/g, 'wekheva')
.replace(/}\.\.\n/g, '}.\n')
.replace(/\.[ ]*?wekheva/g, '. Wekheva')
.replace(/Ji Ji/g, 'Ji')
.replace(/<t:/g, '<w:')
.replace(/<g:/g, '<c:')
// jê bibe
.replace(/\{\{see desc\}\}/g, '')
.replace(/\n\* \{\{rhymes(.+)/g, '')
.replace(/\n\{\{was wotd(.+)/g, '')
.replace(/\n\{\{root\|(.+)(\n)?/g, '')
.replace(/{{enPR\|[^( |\n|,)]+/g, '')
.replace(/\|-}} {{qal\|([^\|]+)\|/g, '|')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:' + title + '|en.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'reformat',
forNamespaces: '0',
accessKey: 'q',
script: function(editor) {
editor
.replace(/\[\[([^\]]+)\]\]\s*(>|→)\s*\[\[([^\]]+)\]\]/g, '\n#: {{qfnim|ku|$1|$3}}')
.replace(/{{ji\|fr}} \[\[([^\]]+)\]\]/g, '{{deyn|fr|ku|$1}}')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[([^\]]+)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\-\]\] \+ \[\[([^\]]+)\]\](\.''|''\.|'')?/g, 'Ji {{navg|ku|$3|-$4-|$5}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\-\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêş|ku|$3-|$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{paş|ku|$3|-$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêk|ku|$3|$4}}.')
.replace(/\* Jihevqetandin: (.+)/g, '* {{ku-kîte}}')
.replace(/==== Ji wêjeyê ====([\s\S]*?)\((.*?)\)\n\n=/g, '==== Ji wêjeyê ====$1{{jêder|$2}}\n\n=')
.replace(/==== Ji wêjeyê ====\n(.+)\n\n{{jêder\|/g, '==== Ji wêjeyê ====\n\* $1 {{jêder|')
.replace(/===(=)?[ ]*?Bi soranî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|ckb}}:')
.replace(/===(=)?[ ]*?Bi zazakî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|zza}}:')
.replace(/''Bin(ê|e)re'': '''\[\[(.*?)\]\]'''/g, '{{guharto|ku|$2}}')
.replace(/fr(e|a)nsî \[\[([^\]]+)\]\](,)? ji latînî \[\[([^\]]+)\]\]/g, '{{ji|fr|ku|$2}}, ji {{ji|la|ku|$4}}')
.replace(/#[ ]*?\{\{bnr(2)?\|(.*?)\}\}(\n\n====[ ]*?Etîmolojî[ ]*?====)?/g, '# {{mane?|ku}}\n\n==== Etîmolojî ====')
.replace(/\{\{bnr(2)?\|(.*?)\}\}(\n\n\[\[Kategorî:Kurdî\]\])?/g, '\n# {{guharto|ku|$2}}')
.replace(/(îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî) \[\[([^\]]+)\]\]/g, '{{hv|{{subst:koda zimanî|$1}}|$2}}')
// .replace(/\[\[([^\]]+)\]\] ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$2}}|$1}}')
// .replace(/\[\[([^\]]+)\]\] \(([^\)]+)\) ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$3}}|$1|tr=$2}}')
.replace(/(avestayî|pehlewî|akadî) \'\'([^\']+)\'\'/g, '{{hv|{{subst:koda zimanî|$1}}||$2|sc=Latn}}')
.replace(/\|îbrî}}/g, '|îbranî}}')
.replace(/(soranî|farisî) {{g\|(ckb|fa)\|([^\}\}]+)}} \(([^\)]+)\)/g, '{{hv|$2|$3|tr=$4}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|ckb|$1|tr=$2}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|fa|$1|tr=$2}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|ckb|$1}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|fa|$1}}')
.replace(/\[\[hevreh\]\]a/g, 'hevreha')
.replace(/\[\[Şablon:(.*?)\|(.*?) (p|r)\.(.*?)\]\]/g, '\n* {{$1|r=$4}}')
.replace(/\[\[Şablon:(.*?)\]\]/g, '\n* {{$1}}')
.replace(/\*[ ]*?\[\[volapûkî\]\]/g, '* {{Z|vo}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\] \(([^\)]+)\)/g, '* {{Z|$1}}: {{W-|$1|$2|tr=$3}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\]/g, '* {{Z|$1}}: {{W-|$1|$2}}')
.replace(/'''(.*?)''':\n{{werger-ser}}/g, '{{werger-ser|$1}}')
.replace(/=== Bilêvkirin ===[ ]*?\n(\*\n[ ]*?)?\n/g, '')
.replace(/==== Bikaranîn ====\n{{\((\|vn=no)?}}/g, '==== Jê ====\n{{($1}}')
.replace(/==== Herwiha ====[ ]*?\n\*[ ]*?\n\n==== Jê ====[ ]*?\n\*[ ]*?\n\n==== Etîmolojî ====[ ]*?/g, '')
.replace(/\*[ ]*?{{ku-ar}}: {{ku-Arab\|\[\[(.*?)\]\]}}/g, '* {{ku-ar}}: {{g|ku|$1|sc=ku-Arab|tr=-}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3|$4}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1}}')
.replace(/\n#:[ ]*?{{hevmane\|ku\|(.*?)}}(,)?[ ]*?\n#:[ ]*?{{hevmane\|ku\|(.*?)}}/g, '\n#: {{hevmane|ku|$1|$3}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}$3\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*/g, '* {{mj|$1}}')
.replace(/\n\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[(.*)\]\]/g, '\n* {{mj|$1}} {{g|ku|$2}}')
.replace(/\n\*[ ]*?\[\[(.*)\]\]/g, '\n* {{g|ku|$1}}')
.replace(/\n(\*|#|#\*|#:)([^( |#\* |#: )])/g, '\n$1 $2')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/,/g, ', ')
.replace(/ ,/g, ',')
.replace(/ [ ]*?/g, ' ')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[z(e|i)lam\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|law}} e.')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[(keç|jin)\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|keç}} e.')
.replace(/(#)?\*?:?[ ]*?''(.*?)''[ ]*?{{jêder\|/g, '$1* {{jêder|ku|jêgirtin=$2|')
.replace(/jêgirtin= /g, 'jêgirtin=')
.replace(/'''[ ]*?Bi (zaravayên din|zazakî)[ ]*?'''/g, '==== Bi zaravayên din ====')
.replace(/Zazakî:/g, '* {{Z|zza}}:')
.replace(/{{navdêr\|ku\|c=-}}/g, '{{ku-tewîn-nav|{{subst:PAGENAME}}|-}}\n{{navdêr|ku|c=m}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin')
.clickDiff();
}
});
pathoschild.TemplateScript.add([
// add your own templates or scripts here
{
name: 'template n',
template: '=={{=nn|{{ucfirst:{{navê zimanî|' + modifiedTitle + '}}}}|' + modifiedTitle + '}}==<noinclude>[[Kategorî:Wîkîferheng:Sernavên zimanan]]</noinclude>',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:=nn|=nn]]}}',
forNamespaces: '10'
},
{
name: 'înterwîkî-çêke',
template: '{{subst:înterwîkî-çêke}}',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:înterwîkî-çêke|subst:înterwîkî-çêke]]}}',
forNamespaces: '14'
},
{
name: 'zimankatbike',
template: '{{zimankatbike|}}',
position: 'cursor',
accessKey: 'f',
forNamespaces: '14'
},
{
category: 'sererastkirin',
name: 'tewîn',
template: '{{ku-tewîn-nav|{{subst:PAGENAME}}|mê}}',
accessKey: '4',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'guharto',
template: '# {{guharto|}}',
position: 'cursor',
accessKey: '',
editSummary: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab|cure=navdêr|c=z|m=m|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab-lêker',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab-lêker|c=h-gh|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'rengdêr',
template: '{{subst:Bikarhêner:Wikihez/preload-rengdêr|ziman=ku|cure=rengdêr}}',
position: 'cursor',
accessKey: '2',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'gp',
template: '{{subst:Bikarhêner:Wikihez/preload-gp}}',
position: 'cursor',
editSummary: '',
forNamespaces: '0'
},
{
category: 'gotûbêj',
name: 'ragihandin',
template: ':{{r| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'outdent',
template: '{{outdent| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'ds',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=standardkirinê|2=DS|meh=Çîriya paşîn|dp=ds|peyitandî=standardkirin|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '1',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'dp',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=peyitandinê|2=DP|meh=Çîriya paşîn|dp=dp|peyitandî=peyitandî|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '2',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'arşîvbin',
template: '{{arşîv-bin}}',
position: 'cursor',
editSummary: 'a',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'xêrhatin',
template: '{{subst:şablon:bixêrhatin/preload}}',
position: 'cursor',
editSummary: 'xêrhatin lê zêde kir',
forNamespaces: 'user talk'
},
{
name: 'nepeyitandî',
template: ':{{nepeyitandî}}--~~~~',
position: 'after',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +{{[[şablon:nepeyitandî|nepeyitandî]]}}',
forNamespaces: '4',
script: function(editor) {
editor
.replace(/== \[\[(.*?)\]\] ==/g, '== <s>\[\[$1\]\]</s> ==');
}
},
{
name: 'jinûvesazî',
template: '{{subst:Bikarhêner:Wikihez/jinûvesazî|ziman=ine-pro|cure=navdêr|peyv= }}',
position: 'cursor',
editSummary: '',
accessKey: '1',
forNamespaces: '108'
},
]);
});
// </nowiki>
3dyz9lgyvcm6cbgw7q3wgp9olpa7115
6241926
6241925
2026-07-12T22:51:10Z
Wikihez
7344
([[m:Special:MyLanguage/User:Jon Harald Søby/diffedit|diffedit]])
6241926
javascript
text/javascript
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
var title = mw.config.get('wgTitle');
// Remove '=' from the title using the replace method
var modifiedTitle = title.replace(/=/g, '');
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
pathoschild.TemplateScript.add({
name:'kolon',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/{{\)}}/g, '}}')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '|$2<q:$1>')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$3<q:$1>')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '|$2')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '|$1')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'nimûne',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/#:\s*'{2}(.*?)'{2}\n/g, '#: {{nm|tr|$1|rêz=1}}\n')
.replace(/#:\s*'{2}(.*?)'{2}\s*\(([^\)]+)\)\.?\n/g, '#: {{nm|tr|$1|$2|rêz=1}}\n')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Formata [[Şablon:nimûne|nimûneyan]]+')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'parentez bike îzah',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\(([^\)]+)\)/g, '{{îzah|$1}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +[[Şablon:îzah|îzah]]')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'bnr bike ku-Latn',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr(2)?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=-}}\n# {{ku-Latn|$2}}\n\n==== Bi alfabeyên din ====\n* {{ku-ar|' + title + '}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: [[Şablon:ku-Latn|{{ku-Latn}}]]+')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'herwiha',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\n{{-}}/g, '')
.replace(/\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$2||$1}}')
.replace(/\*[ ]*?{{g\|(en|tr|de|ku|fa|fr)\|([^\}]+)}}/g, '| {{hw|ku|$2}}')
.replace(/\*[ ]*?\[\[([^\]]+)\]\]/g, '| {{hw|ku|$1}}')
.replace(/{{(\(|stûn)(\|)?(vn=no)?(}})?/g, '{{kol3|ku')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol3\|ku/g, '==== $1 ====\n{{kol3|ku|cure=$1')
.clickDiff();
}
});
pathoschild.TemplateScript.add({
name:'ji dewikt',
// forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{Worttrennung\}\}\n:([\w·]+),\s*\{\{Pl\.\}\}\s*([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}} {{Pl.}} {{kîte|de|$2|nivîs=na}}')
.replace(/\{\{Worttrennung\}\}\n:([\w·]+)/g, '=== Bilêvkirin ===\n* {{kîte|de|$1}}')
.replace(/·/g, '|')
.replace(/\s*\{\{Aussprache}}\s*/g, '\n')
.replace(/:\{\{IPA\}\}\s*\{\{Lautschrift\|([^\}]+)\}\}/g, '* {{IPA|de|[$1]}}')
.replace(/:\{\{Hörbeispiele\}\}\s*\{\{Audio\|([^\}]+)\}\}/g, '* {{deng|de|$1}}')
.replace(/,?\s*\{\{Audio\|([^\|]+)\|spr=at}}/g, '\n* {{deng|de|$1|dever=Awistirya}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[de:' + title + '|de.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'bnr û beralîkirin bike guharto',
forNamespaces: '0',
script: function(editor) {
editor
.replace(/\{\{bnr2?\|(.*?)\}\}/g, '== {{ziman|ku}} ==\n\n=== Navdêr ===\n{{navdêr|ku|c=}}\n# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}')
.replace(/#B?E?R?A?L?Î?K?I?R?I?N? \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
// .replace(/# \[\[([^\]]+)\]\]/g, '# {{guharto|ku|$1}}\n==== Herwiha ====\n\* {{hw|ku|' + title + '}}');
}
});
pathoschild.TemplateScript.add({
name:'bikeKurdî',
accessKey: 'a',
script: function(editor) {
editor
.replace(/Central Iranian:/g, 'Îraniya merkezî')
.replace(/Northeastern Iranian:/g, 'Îraniya bakurêrojhilatî:')
.replace(/Southeastern Iranian:/g, 'Îraniya başûrêrojhilatî:')
.replace(/Northwestern Iranian:/g, 'Îraniya bakurêrojavayî:')
.replace(/Southwestern Iranian:/g, 'Îraniya başûrêrojavayî:')
.replace(/Munji-Yidgha:/g, 'Munjî-Yidghayî:')
.replace(/Kurdish:/g, 'Kurdî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Komisenian:/g, 'Komîsenî:')
.replace(/Mazanderani-Shahmirzadi:/g, 'Mazenderanî-Şahmîrzadî:')
.replace(/Medo-Parthian:/g, 'Medo-partî:')
.replace(/\|kmr(\||\})/g, '|ku$1')
.replace(/\|g(\d+)?=m(\||\})/g, '|c$1=n$2')
.replace(/\|g(\d+)?=f(\||\})/g, '|c$1=m$2')
.replace(/\|g(\d+)?=n(\||\})/g, '|c$1=nt$2')
.replace(/\{\{(a|qualifier|qual|q)\|/g, '{{mj|')
.replace(/\{\{(s|sense)\|/g, '{{mane|')
.replace(/\{\{(af|affix)\|/g, '{{qertaf|')
.replace(/\{\{anagrams\|/g, '{{anagram|')
.replace(/\{\{also\|/g, '{{bnr-h|')
.replace(/\{\{(homophones|homophone|hmp)\|/g, '{{hevdeng|')
.replace(/\{\{(dbt|doublet)\|/g, '{{cotreh|')
.replace(/\{\{alter\|/g, '{{hw|')
.replace(/\{\{alt\|/g, '{{hw|')
.replace(/\{\{(synonyms|syn)\|/g, '{{hevmane|')
.replace(/\{\{(antonyms|antonym|ant)\|/g, '{{dijmane|')
.replace(/\{\{(hyponyms|hypo)\|/g, '{{jêrnav|')
.replace(/\{\{(hypernyms|hyper)\|/g, '{{jornav|')
.replace(/\{\{(coordinate terms|cot)\|/g, '{{koordîne|')
.replace(/\{\{(inline alt forms|alti)\|/g, '{{herwiha-rêz|')
.replace(/\{\{(hyphenation|hyph)\|/g, '{{kîte|')
.replace(/\{\{(back-form|back-formation|bf)\|/g, '{{paşvesazî|')
.replace(/\{\{l\|/g, '{{g|')
.replace(/\{\{m\|/g, '{{qal|')
.replace(/\{\{(label|lb)\|/g, '{{e|')
.replace(/\|(UK|RP)(\||\}\})/g, '|QY$2')
.replace(/\|AU(\||\}\})/g, '|Awistralya$1')
.replace(/\|Australia(\||\}\})/g, '|Awistralya$1')
.replace(/\|mul(\||\}\})/g, '|navz$1')
.replace(/\|Canada(\||\}\})/g, '|Kanada$1')
.replace(/\|informal(\||\}\})/g, '|neresmî$1')
.replace(/\|rare(\||\}\})/g, '|kêmpeyda$1')
.replace(/\|archaic(\||\}\})/g, '|kevnare$1')
.replace(/\|slang(\||\}\})/g, '|argo$1')
.replace(/\|idiomatic(\||\}\})/g, '|biwêjî$1')
.replace(/\|obsolete(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|dated(\||\}\})/g, '|kevnbûyî$1')
.replace(/\|(US|USA|GenAm|GA)(\||\}\})/g, '\|DYA$2')
.replace(/\{\{audio\|/g, '{{deng|')
.replace(/\|[ ]*a[ ]*=[ ]*(US|USA|GA|GenAm)/g, '|dever=DYA')
.replace(/\|[ ]*a[ ]*=[ ]*Southern England/g, '|dever=Îngilistana başûr')
.replace(/\|[ ]*a[ ]*=[ ]*(UK|RP)/g, '|dever=QY')
.replace(/\|[ ]*a[ ]*=[ ]*AU/g, '|dever=Awistralya')
.replace(/[aA]udio \((UK|RP)\)/g, 'Deng (QY\)')
.replace(/\|[aA]udio \(Southern England\)\}\}/g, '\|Deng \(Îngilistana başûr\)}\}')
.replace(/[aA]udio \(AU\)/g, 'Deng \(Awistralya\)')
.replace(/[aA]udio \((US|USA|GA|GenAm)\)/g, 'Deng \(DYA\)')
.replace(/===(=)?(=)?Verb===(=)?(=)?\n{{head\|en\|verb form}}/g, '=== Formeke lêkerê ===\n{{lêker|en|form=erê}}')
.replace(/===(=)?(=)?Noun===(=)?(=)?\n{{head\|en\|noun form}}/g, '=== Formeke navdêrê ===\n{{navdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adjective===(=)?(=)?\n{{head\|en\|(comparative|superlative) adjective}}/g, '=== Formeke rengdêrê ===\n{{rengdêr|en|form=erê}}')
.replace(/===(=)?(=)?Adverb===(=)?(=)?\n{{head\|en\|(comparative|superlative) adverb}}/g, '=== Formeke hokerê ===\n{{hoker|en|form=erê}}')
.replace(/===(=)?(=)?Synonyms===(=)?(=)?/g, '==== Hevmane ====')
.replace(/===(=)?(=)?Coordinate terms===(=)?(=)?/g, '==== Termên koordîne ====')
.replace(/===(=)?(=)?Antonyms===(=)?(=)?/g, '==== Dijmane ====')
.replace(/===(=)?(=)?Descendants===(=)?(=)?/g, '==== Dûnde ====')
.replace(/===(=)?(=)?Derived terms===(=)?(=)?/g, '==== Jê ====')
.replace(/===(=)?(=)?Alternative forms===(=)?(=)?/g, '==== Herwiha ====')
.replace(/===(=)?(=)?Related terms===(=)?(=)?/g, '==== Têkildar ====')
.replace(/===(=)?(=)?See also===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Anagrams===(=)?(=)?/g, '==== Anagram ====')
.replace(/===(=)?(=)?Further reading===(=)?(=)?/g, '==== Binêre herwiha ====')
.replace(/===(=)?(=)?Pronunciation(.*?)===(=)?(=)?/g, '=== Bilêvkirin ===')
.replace(/===(=)?(=)?Etymology(.*?)===(=)?(=)?/g, '==== Etîmolojî ====')
.replace(/===(=)?(=)?Hyponyms===(=)?(=)?/g, '==== Jêrnav ====')
.replace(/===(=)?(=)?Hypernyms===(=)?(=)?/g, '==== Jornav ====')
.replace(/===(=)?(=)?Proper (n|N)oun===(=)?(=)?/g, '=== Serenav ===')
.replace(/===(=)?(=)?Adjective===(=)?(=)?/g, '=== Rengdêr ===')
.replace(/===(=)?(=)?Adverb===(=)?(=)?/g, '=== Hoker ===')
.replace(/===(=)?(=)?Verb===(=)?(=)?/g, '=== Lêker ===')
.replace(/===(=)?(=)?Noun===(=)?(=)?/g, '=== Navdêr ===')
.replace(/^==([^=]+)==$/gm, '== {{ziman|{{subst:en-to-kod|$1}}}} ==')
.replace(/\{\{en-noun(.*?)/g, '{{en-navdêr$1')
.replace(/\{\{en-verb(.*?)/g, '{{en-lêker$1')
.replace(/\{\{en-adv(.*?)/g, '{{en-hoker$1')
.replace(/\{\{en-adj(.*?)/g, '{{en-rengdêr$1')
.replace(/\{\{en-proper noun(.*?)/g, '{{en-serenav$1')
.replace(/\{\{en-plural( |\-)noun\}\}/g, '{{navdêr|en|j=p}}')
.replace(/\{\{(pre|prefix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêş\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(suf|suffix)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{paş\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(com|compound)\|(.*?)\|(.*?)\|(.*?)\}\}/g, 'Ji \{\{pêk\|$2\|$3\|$4\}\}\.')
.replace(/\{\{(con|confix)\|/g, 'Ji \{\{pêşûpaş|')
.replace(/\n# \{\{(alt|alternative) (spelling|form)( of)?\|/g, '# {{awayekî din|')
.replace(/\{\{(wp|wikipedia)\}\}/g, '{{wp|ziman=en}}')
.replace(/\{\{(pedia|pedialite)\}\}/g, '{{wpedî|ziman=en}}')
.replace(/\{\{(der|rel|col)\d\|/g, '{{kol3|')
.replace(/====[ ]*?(Herwiha|Jê|Têkildar)[ ]*?====\n{{kol(2|3)\|en/g, '==== $1 ====\n{{kol$2|en|cure=$1')
.replace(/\n# \{\{infl of\|en\|(.*?)\|\|ing-form\}\}/g, '# {{partîsîpa niha|en|$1}}')
.replace(/\n# \{\{past participle of\|en\|(.*?)\|nocat=1\}\}/g, '# {{partîsîpa borî|en|$1}}')
.replace(/\n# \{\{en-past of\|/g, '# {{en-dema-borî|')
.replace(/\n# \{\{en-simple past of\|/g, '# {{en-dema-borî-sade|')
.replace(/\n# \{\{en-third-person singular of\|(.*?)\}\}/g, '# {{en-dema-niha|$1|sêyem|yekjimar}}')
.replace(/\n# \{\{plural of\|/g, '# {{pirjimar|')
.replace(/\n# \{\{en-superlative of\|/g, '# {{sûperlatîv|en|')
.replace(/\n# \{\{en-comparative of\|/g, '# {{komparatîv|en|')
.replace(/\n# \{\{(obs|obsolete|dated) (spelling|form)( of)\|/g, '# {{kevnbûyî|')
.replace(/\{\{bor\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{deyn|$2|$1$3')
.replace(/\{\{inh\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{mîr|$2|$1$3')
.replace(/\{\{u?der\+?\|(.*?)\|(.*?)(\}\}|\|)/g, '{{ji|$2|$1$3')
.replace(/\{\{etyl\|(.*?)\|(.*?)\}\}/g, '{{ji|$1|$2|-}}')
.replace(/\{\{(cog|cognate)\|/g, '{{hv|')
.replace(/\{\{(noncognate|noncog|ncog|nc)\|/g, '{{nh|')
.replace(/\{\{surf\|/g, '{{anlz|')
.replace(/\{\{desc\|/g, '{{dû|')
.replace(/\{\{desctree\|/g, '{{dardû|')
.replace(/bor=1/g, 'deyn=1')
.replace(/nocat=1/g, 'nekat=1')
.replace(/\|(t|gloss)([1-9][0-9]*)?=/g, '|w$2=')
.replace(/\|alt([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/\|head([1-9][0-9]*)?=/g, '|cuda$1=')
.replace(/bor=1/g, 'deyn=1')
.replace(/\[\[(Image|File):/g, '\[\[Wêne:')
.replace(/\*[ ]*?\[\[(.*)\]\]/g, '* {{g|en|$1}}')
.replace(/#\*[ ]*?'''([0-9]+)''' (.*?)\n#(\*)?:(.+)/g, '#* $4 {{jêder|$2, $1}}')
.replace(/=\nFrom/g, '=\nJi')
.replace(/}(,)? from {/g, '}, ji {')
.replace(/=\nBorrowed from/g, '=\nDeyn ji')
.replace(/(e|E)quivalent to( Ji)?/g, 'wekheva')
.replace(/}\.\.\n/g, '}.\n')
.replace(/\.[ ]*?wekheva/g, '. Wekheva')
.replace(/Ji Ji/g, 'Ji')
.replace(/<t:/g, '<w:')
.replace(/<g:/g, '<c:')
// jê bibe
.replace(/\{\{see desc\}\}/g, '')
.replace(/\n\* \{\{rhymes(.+)/g, '')
.replace(/\n\{\{was wotd(.+)/g, '')
.replace(/\n\{\{root\|(.+)(\n)?/g, '')
.replace(/{{enPR\|[^( |\n|,)]+/g, '')
.replace(/\|-}} {{qal\|([^\|]+)\|/g, '|')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:' + title + '|en.wikt]]')
.clickPreview();
}
});
pathoschild.TemplateScript.add({
name:'reformat',
forNamespaces: '0',
accessKey: 'q',
script: function(editor) {
editor
.replace(/\[\[([^\]]+)\]\]\s*(>|→)\s*\[\[([^\]]+)\]\]/g, '\n#: {{qfnim|ku|$1|$3}}')
.replace(/{{ji\|fr}} \[\[([^\]]+)\]\]/g, '{{deyn|fr|ku|$1}}')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[([^\]]+)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\-\]\] \+ \[\[([^\]]+)\]\](\.''|''\.|'')?/g, 'Ji {{navg|ku|$3|-$4-|$5}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\-\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêş|ku|$3-|$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[\-(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{paş|ku|$3|-$4}}.')
.replace(/(\*|#)?(Ji '')?[ ]*?\[\[(.*?)\]\][ ]*?\+[ ]*?\[\[(.*?)\]\](\.''|''\.|'')?/g, 'Ji {{pêk|ku|$3|$4}}.')
.replace(/\* Jihevqetandin: (.+)/g, '* {{ku-kîte}}')
.replace(/==== Ji wêjeyê ====([\s\S]*?)\((.*?)\)\n\n=/g, '==== Ji wêjeyê ====$1{{jêder|$2}}\n\n=')
.replace(/==== Ji wêjeyê ====\n(.+)\n\n{{jêder\|/g, '==== Ji wêjeyê ====\n\* $1 {{jêder|')
.replace(/===(=)?[ ]*?Bi soranî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|ckb}}:')
.replace(/===(=)?[ ]*?Bi zazakî[ ]*?(=)?===\n\*/g, '==== Bi zaravayên din ====\n* {{Z|zza}}:')
.replace(/''Bin(ê|e)re'': '''\[\[(.*?)\]\]'''/g, '{{guharto|ku|$2}}')
.replace(/fr(e|a)nsî \[\[([^\]]+)\]\](,)? ji latînî \[\[([^\]]+)\]\]/g, '{{ji|fr|ku|$2}}, ji {{ji|la|ku|$4}}')
.replace(/#[ ]*?\{\{bnr(2)?\|(.*?)\}\}(\n\n====[ ]*?Etîmolojî[ ]*?====)?/g, '# {{mane?|ku}}\n\n==== Etîmolojî ====')
.replace(/\{\{bnr(2)?\|(.*?)\}\}(\n\n\[\[Kategorî:Kurdî\]\])?/g, '\n# {{guharto|ku|$2}}')
.replace(/(îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî) \[\[([^\]]+)\]\]/g, '{{hv|{{subst:koda zimanî|$1}}|$2}}')
// .replace(/\[\[([^\]]+)\]\] ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$2}}|$1}}')
// .replace(/\[\[([^\]]+)\]\] \(([^\)]+)\) ya (îbrî|îtalî|fransî|sanskrîtî|ermenî|tirkî|rûsî|spanî|aramî|yûnaniya kevn|yewnaniya kevn|rusî|polonî|inglîziya kevn|almanî|swêdî|lîtwanî|latînî|inglîzî)/g, '{{hv|{{subst:koda zimanî|$3}}|$1|tr=$2}}')
.replace(/(avestayî|pehlewî|akadî) \'\'([^\']+)\'\'/g, '{{hv|{{subst:koda zimanî|$1}}||$2|sc=Latn}}')
.replace(/\|îbrî}}/g, '|îbranî}}')
.replace(/(soranî|farisî) {{g\|(ckb|fa)\|([^\}\}]+)}} \(([^\)]+)\)/g, '{{hv|$2|$3|tr=$4}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|ckb|$1|tr=$2}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}} \(([^\)]+)\)/g, '{{hv|fa|$1|tr=$2}}')
.replace(/soranî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|ckb|$1}}')
.replace(/farisî {{ku-Arab\|\[\[([^\]\]]+)\]\]}}/g, '{{hv|fa|$1}}')
.replace(/\[\[hevreh\]\]a/g, 'hevreha')
.replace(/\[\[Şablon:(.*?)\|(.*?) (p|r)\.(.*?)\]\]/g, '\n* {{$1|r=$4}}')
.replace(/\[\[Şablon:(.*?)\]\]/g, '\n* {{$1}}')
.replace(/\*[ ]*?\[\[volapûkî\]\]/g, '* {{Z|vo}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\] \(([^\)]+)\)/g, '* {{Z|$1}}: {{W-|$1|$2|tr=$3}}')
.replace(/\* {{Z\|([^\}]+)}}: \[\[([^\]]+)\]\]/g, '* {{Z|$1}}: {{W-|$1|$2}}')
.replace(/'''(.*?)''':\n{{werger-ser}}/g, '{{werger-ser|$1}}')
.replace(/=== Bilêvkirin ===[ ]*?\n(\*\n[ ]*?)?\n/g, '')
.replace(/==== Bikaranîn ====\n{{\((\|vn=no)?}}/g, '==== Jê ====\n{{($1}}')
.replace(/==== Herwiha ====[ ]*?\n\*[ ]*?\n\n==== Jê ====[ ]*?\n\*[ ]*?\n\n==== Etîmolojî ====[ ]*?/g, '')
.replace(/\*[ ]*?{{ku-ar}}: {{ku-Arab\|\[\[(.*?)\]\]}}/g, '* {{ku-ar}}: {{g|ku|$1|sc=ku-Arab|tr=-}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3|$4}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2|$3}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\],[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1|$2}}')
.replace(/\n#:[ ]*?\[\[([^\]]+)\]\](,)?/g, '\n#: {{hevmane|ku|$1}}')
.replace(/\n#:[ ]*?{{hevmane\|ku\|(.*?)}}(,)?[ ]*?\n#:[ ]*?{{hevmane\|ku\|(.*?)}}/g, '\n#: {{hevmane|ku|$1|$3}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}$3\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*(.+)\n\*/g, '* {{mj|$1}}$2\n* {{mj|$1}}')
.replace(/''(Navdêr|Rengdêr|Lêker)'':\n\*/g, '* {{mj|$1}}')
.replace(/\n\*[ ]*?{{mj\|(.*?)}}[ ]*?\[\[(.*)\]\]/g, '\n* {{mj|$1}} {{g|ku|$2}}')
.replace(/\n\*[ ]*?\[\[(.*)\]\]/g, '\n* {{g|ku|$1}}')
.replace(/\n(\*|#|#\*|#:)([^( |#\* |#: )])/g, '\n$1 $2')
.replace(/{{mj\|Lêker}}/g, '{{mj|lêker}}')
.replace(/{{mj\|Navdêr}}/g, '{{mj|navdêr}}')
.replace(/{{mj\|Rengdêr}}/g, '{{mj|rengdêr}}')
.replace(/,/g, ', ')
.replace(/ ,/g, ',')
.replace(/ [ ]*?/g, ' ')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[z(e|i)lam\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|law}} e.')
.replace(/('')?\[\[nav\]\]ek(î)? \[\[(keç|jin)\]\]an[ ]*?e(\.)?('')?/g, '[[nav|Navekî]] {{navkes|ku|keç}} e.')
.replace(/(#)?\*?:?[ ]*?''(.*?)''[ ]*?{{jêder\|/g, '$1* {{jêder|ku|jêgirtin=$2|')
.replace(/jêgirtin= /g, 'jêgirtin=')
.replace(/'''[ ]*?Bi (zaravayên din|zazakî)[ ]*?'''/g, '==== Bi zaravayên din ====')
.replace(/Zazakî:/g, '* {{Z|zza}}:')
.replace(/{{navdêr\|ku\|c=-}}/g, '{{ku-tewîn-nav|{{subst:PAGENAME}}|-}}\n{{navdêr|ku|c=m}}')
.appendEditSummary('[[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin')
.clickDiff();
}
});
pathoschild.TemplateScript.add([
// add your own templates or scripts here
{
name: 'template n',
template: '=={{=nn|{{ucfirst:{{navê zimanî|' + modifiedTitle + '}}}}|' + modifiedTitle + '}}==<noinclude>[[Kategorî:Wîkîferheng:Sernavên zimanan]]</noinclude>',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:=nn|=nn]]}}',
forNamespaces: '10'
},
{
name: 'înterwîkî-çêke',
template: '{{subst:înterwîkî-çêke}}',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: {{[[Şablon:înterwîkî-çêke|subst:înterwîkî-çêke]]}}',
forNamespaces: '14'
},
{
name: 'zimankatbike',
template: '{{zimankatbike|}}',
position: 'cursor',
accessKey: 'f',
forNamespaces: '14'
},
{
category: 'sererastkirin',
name: 'tewîn',
template: '{{ku-tewîn-nav|{{subst:PAGENAME}}|mê}}',
accessKey: '4',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'guharto',
template: '# {{guharto|}}',
position: 'cursor',
accessKey: '',
editSummary: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab|cure=navdêr|c=z|m=m|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'ku-arab-lêker',
template: '{{subst:Bikarhêner:Wikihez/preload-gotar-ku-arab-lêker|c=h-gh|peyv=}}',
position: 'cursor',
accessKey: '',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'rengdêr',
template: '{{subst:Bikarhêner:Wikihez/preload-rengdêr|ziman=ku|cure=rengdêr}}',
position: 'cursor',
accessKey: '2',
forNamespaces: '0'
},
{
category: 'sererastkirin',
name: 'gp',
template: '{{subst:Bikarhêner:Wikihez/preload-gp}}',
position: 'cursor',
editSummary: '',
forNamespaces: '0'
},
{
category: 'gotûbêj',
name: 'ragihandin',
template: ':{{r| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'outdent',
template: '{{outdent| }}',
position: 'cursor',
editSummary: '',
forNamespaces: [3, 4, 5]
},
{
category: 'gotûbêj',
name: 'ds',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=standardkirinê|2=DS|meh=Çîriya paşîn|dp=ds|peyitandî=standardkirin|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '1',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'dp',
template: '{{subst:Bikarhêner:Wikihez/preload-arşîv|1=peyitandinê|2=DP|meh=Çîriya paşîn|dp=dp|peyitandî=peyitandî|hejmar=|gotar={{subst:PAGENAME}}}}',
position: 'cursor',
editSummary: 'arşîvkirin',
accessKey: '2',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'arşîvbin',
template: '{{arşîv-bin}}',
position: 'cursor',
editSummary: 'a',
forNamespaces: 'talk'
},
{
category: 'gotûbêj',
name: 'xêrhatin',
template: '{{subst:şablon:bixêrhatin/preload}}',
position: 'cursor',
editSummary: 'xêrhatin lê zêde kir',
forNamespaces: 'user talk'
},
{
name: 'nepeyitandî',
template: ':{{nepeyitandî}}--~~~~',
position: 'after',
editSummary: '[[Bikarhêner:Wikihez/templateScript2.js|TS]]: +{{[[şablon:nepeyitandî|nepeyitandî]]}}',
forNamespaces: '4',
script: function(editor) {
editor
.replace(/== \[\[(.*?)\]\] ==/g, '== <s>\[\[$1\]\]</s> ==');
}
},
{
name: 'jinûvesazî',
template: '{{subst:Bikarhêner:Wikihez/jinûvesazî|ziman=ine-pro|cure=navdêr|peyv= }}',
position: 'cursor',
editSummary: '',
accessKey: '1',
forNamespaces: '108'
},
]);
});
// </nowiki>
92ti8l4h3dexm1eevlp5abvymnyu682
Bikarhêner:Wikihez/test.js
2
969083
6241757
6241752
2026-07-12T12:09:33Z
Wikihez
7344
6241757
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
* Output per citation:
* #* <quote>
* #*: '''<quoteTr>''' (if transliteration present)
* #*: <quoteT> (if translation present)
* #** {{jêder-…|lang|jêgirtin=…|…fields…}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
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;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName) {
obj.jêderTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jêderTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jêderTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
16zgmz065jkpdw30ehdgq6ir5qonfgv
6241758
6241757
2026-07-12T12:16:34Z
Wikihez
7344
6241758
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the quote is written out directly instead:
* #* <quote>
* #*: '''<quoteTr>''' (if transliteration present)
* #*: <quoteT> (if translation present)
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
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 += "}}";
return cite;
}
var out = "\n#* " + jeder.quote;
if (jeder.quoteTr) out += "\n#*: '''" + jeder.quoteTr + "'''";
if (jeder.quoteT) out += "\n#*: " + jeder.quoteT;
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName) {
obj.jêderTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jêderTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jêderTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
2d65hr51gotkhwu5d29t6ay4rtoab4n
6241760
6241758
2026-07-12T12:21:29Z
Wikihez
7344
6241760
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the quote is written out directly instead:
* #* <quote>
* #*: '''<quoteTr>''' (if transliteration present)
* #*: <quoteT> (if translation present)
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang; + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
out += "|çavkanî?}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName) {
obj.jêderTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jêderTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jêderTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
q1ebn9od658dy9fgagmsimk86gmpuf9
6241761
6241760
2026-07-12T12:30:52Z
Wikihez
7344
6241761
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the quote is written out directly instead:
* #* <quote>
* #*: '''<quoteTr>''' (if transliteration present)
* #*: <quoteT> (if translation present)
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang; + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
out += "|çavkanî?}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
otz5aizybu97jpbemm7vbuvbhvhflwo
6241762
6241761
2026-07-12T12:32:11Z
Wikihez
7344
6241762
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead, with a placeholder |çavkanî? for the (missing) source:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|çavkanî?}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
out += "|çavkanî?}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
c6pqq44es5tkz7y2gw2n5y2qd67okf0
6241764
6241762
2026-07-12T12:41:23Z
Wikihez
7344
6241764
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
out += "|" + (jeder.jederManual ? jeder.jederManual : "çavkanî?");
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
b08qzdns5bmzzyqhac2lh5jktcom0vp
6241765
6241764
2026-07-12T12:44:48Z
Wikihez
7344
6241765
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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
7ktw53oklsogzd4z7r9gwmiodj5xw9g
6241771
6241765
2026-07-12T12:48:54Z
Wikihez
7344
6241771
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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
0zkgcn6nnodr073uc9l4tyf2a63oqxh
6241784
6241771
2026-07-12T13:23:48Z
Wikihez
7344
6241784
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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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) {
// 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
}
});
if (values.lang !== "ku" && !hasTemplateSense ) 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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
n9xo4k8zx94hwbzyasgkpjgzzc7sonc
6241786
6241784
2026-07-12T13:24:26Z
Wikihez
7344
Restored revision 6241771 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]])
6241786
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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
0zkgcn6nnodr073uc9l4tyf2a63oqxh
6241794
6241786
2026-07-12T13:33:53Z
Wikihez
7344
6241794
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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 only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var rows = steps.trans.getTranslations(stepDiv);
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
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");
});
}
var wordLines = $.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");
// The translations entered in this wizard aren't tied to a
// specific sense, so they're attached under the first gloss;
// any further glosses get an empty pair ready for the editor
// to fill in per sense.
var blocks = $.map(glosses, function (gloss, gi) {
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (gi === 0 && wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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>
pp77gi39hrf8e5mud42kmxhv0vhtdtw
6241802
6241794
2026-07-12T13:55:39Z
Wikihez
7344
6241802
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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 only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
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(group, 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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").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>
d44lrlfzv1sf5tt0sgc650j0y8tvzal
6241810
6241802
2026-07-12T14:06:28Z
Wikihez
7344
6241810
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// One bullet per word — unlike Werger, words aren't grouped
// together on a single line per language.
var lines = [];
$.each(rows, function (_, row) {
var lang = row[0], words = row[1];
$.each(words, function (_, w) {
lines.push("* {{dû|" + lang + "|" + w + "}}");
});
});
if (!lines.length) return "";
return "\n\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
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(group, 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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
f882z9uthm2ubgufwvw5sqkih8u4b5b
6241812
6241810
2026-07-12T14:13:54Z
Wikihez
7344
6241812
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
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(group, 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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
t9u0eqi6glumlnjd5dpo05da0tjur7c
6241813
6241812
2026-07-12T14:22:22Z
Wikihez
7344
6241813
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
knsbz9g2167fw6mrujto7v9nua81e3j
6241815
6241813
2026-07-12T15:01:45Z
Wikihez
7344
6241815
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
qvdl3xftbxk0kf1saacawiqd4ghmi3p
6241816
6241815
2026-07-12T15:16:36Z
Wikihez
7344
6241816
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// or empty — i.e. there is no real gloss anywhere to attach a
// translation table to. A mix of real + template senses still
// shows Werger; the template senses are simply skipped in output().
var hasRealSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
});
return hasRealSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
j6z44rqszftbvbj6z4of6jwrhrnvx93
6241820
6241816
2026-07-12T15:43:43Z
Wikihez
7344
6241820
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
$.each(dfnSenses, function (i, s) {
if (s.tpl) return; // template sense — no gloss to caption with
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense (or nothing filled in) — there's
// no real gloss anywhere, so skip the section entirely rather than
// emitting an empty {{werger-ser}}/{{werger-bin}} pair.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + gloss.text + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
return "\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
902aq6e4et3ize1j3dory5725v7ehju
6241824
6241820
2026-07-12T15:50:47Z
Wikihez
7344
6241824
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, "\\$&");
}
// [[armanc|xuyang]] -> xuyang ; [[armanc]] -> armanc. Ji bo sernavê
// {{werger-ser|mane|jimare}} pêwîst e, çimkî mane bi xwe nikare girêdanên
// wikî hilgire (ew tenê di dawiya tevahiya deqê de bi linkify tên zêdekirin).
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* 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 û ti jêder jî tinebe, {{bênimûne|lang}} tê nivîsandin —
* heke sense xwedan jêder be, jêder bi xwe wek nimûne dihat hesibandin, loma
* pêwîst nake.
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* When a citation template is chosen, it fully replaces the raw quote/tr/t
* lines (the template itself carries jêgirtin=/tr=/tercime=):
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).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);
}
});
// — Jêder (quote / citation) group — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
t92stfvtgqiyqv2lktbjcbtjyswnrin
6241853
6241824
2026-07-12T19:10:44Z
Wikihez
7344
6241853
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
mb00jlk3wxj5q2k4670ury7rodgv75b
6241854
6241853
2026-07-12T19:13:26Z
Wikihez
7344
6241854
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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");
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;
}
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");
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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêder: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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…");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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î)…")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return values.lang === "ku" && !!values.pos;
},
disabledKeys: {
"navz": true,
"ku": true },
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Peyv…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + ". " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += ".";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
ihxuq612gs1nzpn5zm6qfybgye6asmq
6241855
6241854
2026-07-12T19:34:28Z
Wikihez
7344
6241855
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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");
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", "Mîsala emilandina kelîmeyê tu bi xwe binivîse…");
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îpsiyona bi alfabeya latînî")
);
}
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", "Tercimeya kurmancî")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
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");
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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêgirtin: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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", "Mîsala emilandinê ji kitêb an çavkaniyeke din binivîse");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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ê bi kurmancî")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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("koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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", "Nimûne: Ji {{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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return !!values.pos;
},
disabledKeys: {
"navz": true},
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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î lê bigere");
populateMenus(langSel, steps.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Kelîme…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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) {
var stepDiv = $("#wiktku-start-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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î lê bigere");
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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + " " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += "";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
lx2xjn01myh0ug7ewhkkbuua7tq81mq
6241856
6241855
2026-07-12T19:45:35Z
Wikihez
7344
6241856
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + header + "\n" +
$.map(words, function (w) {
return "|" + w;
}).join("\n");
return section +
"{{kol3|" + lang + "\n" + params + "\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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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");
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ûneya emilandina kelîmeyê tu bi xwe binivîse…");
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îpsiyona bi alfabeya latînî")
);
}
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", "Tercimeya kurmancî")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
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");
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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêgirtin: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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", "Nimûneya emilandinê ji kitêb an çavkaniyeke din binivîse");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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ê bi kurmancî")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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("koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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", "Nimûne: Ji {{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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return !!values.pos;
},
disabledKeys: {
"navz": true},
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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î lê bigere");
populateMenus(langSel, steps.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Kelîme…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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) {
var stepDiv = $("#wiktku-start-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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î lê bigere");
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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + " " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += "";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
btrz4jgandrnlsizofa7xfj2xe6a3sr
6241857
6241856
2026-07-12T19:57:18Z
Wikihez
7344
6241857
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + 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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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");
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ûneya emilandina kelîmeyê tu bi xwe binivîse…");
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îpsiyona bi alfabeya latînî")
);
}
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", "Tercimeya kurmancî")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
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");
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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêgirtin: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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", "Nimûneya emilandinê ji kitêb an çavkaniyeke din binivîse");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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ê bi kurmancî")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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("koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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", "Nimûne: Ji {{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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return !!values.pos;
},
disabledKeys: {
"navz": true},
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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î lê bigere");
populateMenus(langSel, steps.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Kelîme…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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) {
var stepDiv = $("#wiktku-start-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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î lê bigere");
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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + " " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += "";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
ntu65wamh1lvn2ois7xdc5oyul6x4p5
6241866
6241857
2026-07-12T20:51:59Z
Wikihez
7344
6241866
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + 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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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, izah: "xisûsen, resmî, anatomî, Mêrdîn, Badînî" },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, izah: "Varyantên vê kelîmeyê" },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, izah: "Spehî hevmaneya Bedew e." },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, izah: "Zengîn dijmaneya feqîr e." },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, izah: "Pisîk û kûçik termên koordîne ne çunkî Jornavên wan gelek in" },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, izah: "Heywan jornavê guhandar e" },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, izah: "Guhandar jêrnavê heywan e" },
{ 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");
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ûneya emilandina kelîmeyê tu bi xwe binivîse…");
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îpsiyona bi alfabeya latînî")
);
}
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", "Tercimeya kurmancî")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
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 + ": " + g.izah);
var list = $("<ol></ol>").addClass("wiktku-dfn-sublist " + g.cls + "-list");
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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêgirtin: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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", "Nimûneya emilandinê ji kitêb an çavkaniyeke din binivîse");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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ê bi kurmancî")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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("koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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", "Nimûne: Ji {{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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return !!values.pos;
},
disabledKeys: {
"navz": true},
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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î lê bigere");
populateMenus(langSel, steps.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Kelîme…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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) {
var stepDiv = $("#wiktku-start-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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î lê bigere");
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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + " " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += "";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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û]] v.2.0) +" +
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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
26h28kz7q8aw7pkd3d1x3irkuvgkhha
6241867
6241866
2026-07-12T20:53:48Z
Wikihez
7344
6241867
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.
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, "\\$&");
}
function stripWikilinks(str) {
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) {
return display || target;
});
}
/**
* Nivîsek li cihê kursora tekstareayek 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;
}
var pageName = mw.config.get("wgPageName").replaceAll(/_/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
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.
*/
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 îzaha maneyê 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 sisêyan a şablonê, bê nav)
*/
function formatNimune(nimunes, lang, hasJeder) {
var hasNimune = nimunes && $.grep(nimunes, function (n) {
return (typeof n === "object" ? n.text : n) !== "";
}).length > 0;
if (!hasNimune) {
return hasJeder ? "" : "\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 list of jêder (quote/citation) objects into wikitext lines.
* Each entry that has no quote text is skipped. Returns "" when the list
* is empty or every entry is blank.
*
* #* {{jêder-…|lang|jêgirtin=…|tr=…|tercime=…|…fields…}}
*
* When no template is chosen, the generic {{jêder|…}} template is used
* instead. Its 2nd positional param is the user's freeform "bi destê xwe
* binivîsim" source text when supplied, or the çavkanî? placeholder otherwise.
* If that text contains "=" it is passed as |2=… instead of a bare
* positional param, since MediaWiki would otherwise misparse it as its
* own key=value pair and break the template:
* #* {{jêder|lang|jêgirtin=…|tr=…|tercime=…|<manual source or çavkanî?>}}
*/
function formatJeder(jederList, lang) {
if (!jederList || !jederList.length) return "";
return $.map(jederList, function (jeder) {
if (!jeder || !jeder.quote) return undefined;
if (jeder.jederTpl) {
var cite = "\n#* {{" + jeder.jederTpl + "|" + 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 += "}}";
return cite;
}
var out = "\n#* {{jêder|" + lang + "|jêgirtin=" + jeder.quote;
if (jeder.quoteTr) out += "|tr=" + jeder.quoteTr;
if (jeder.quoteT) out += "|tercime=" + jeder.quoteT;
var srcParam = jeder.jederManual ? jeder.jederManual : "çavkanî?";
// A positional param containing "=" gets parsed as its own key=value
// pair by MediaWiki and breaks the template, so force it to be
// explicitly named (|2=) whenever that's the case.
out += (srcParam.indexOf("=") !== -1 ? "|2=" : "|") + srcParam;
out += "}}";
return out;
}).join("");
}
/**
* Fabrîkeyek bo gavên "lîsteya kelîmeyan" ên dişibin hev: jê, têkildar, binêre herwiha.
*/
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 = "|cure=" + 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", "Nimûne: {{IPA|ku|/pɛɪ̯n/}} yan {{kîte|ku|he|ce|ki|rin}}");
// 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(/CODE/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";
// Add ku-tewîn-nav for single-word navdêr/serenav with known gender.
if (!pageName.includes(" ") && cinsiyet && GENDER_BASE_LABELS[cinsiyet] &&
(pos === "navdêr" || pos === "serenav") && values.lang === "ku") {
outputString += "{{ku-tewîn-nav|" + pageName + "|" + GENDER_BASE_LABELS[cinsiyet];
if (pos === "serenav") outputString += "|y";
outputString += "}}\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. Opsiyonên vê gavê ne sabît in — ji metadata[values.lang].g
* têne çêkirin, ji ber ku di hemû zimanan de cinsiyet tine.
*/
cinsiyet: {
id: "cinsiyet",
name: "cinsiyet",
question_fmt: 'Cinsiyeta "' + pageName + '" ç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);
}
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.
*/
lektur: {
id: "lektur",
name: "Cureyê lêkerê (fiîlê)",
question_fmt: "Cureyê lêkerê (fiîlê) ç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: "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin! 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 examples = steps.dfn.posExamples || {};
var full = values.pos || "";
return examples[full] || "";
},
/**
* 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=''>— yan jî ş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();
// — 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, izah: "xisûsen, resmî, anatomî, Mêrdîn, Badînî" },
{ cls: "wiktku-dfn-herwiha", label: "Herwiha", rows: 1, narrow: true, izah: "Varyantên vê kelîmeyê" },
{ cls: "wiktku-dfn-hevmane", label: "Hevmane", rows: 1, narrow: true, izah: "Spehî hevmaneya Bedew e." },
{ cls: "wiktku-dfn-dijmane", label: "Dijmane", rows: 1, narrow: true, izah: "Zengîn dijmaneya feqîr e." },
{ cls: "wiktku-dfn-koordine", label: "Termên koordîne", rows: 1, narrow: true, izah: "Pisîk û kûçik termên koordîne ne çunkî Jornavên wan gelek in" },
{ cls: "wiktku-dfn-jornav", label: "Jornav", rows: 1, narrow: true, izah: "Heywan jornavê guhandar e" },
{ cls: "wiktku-dfn-jernav", label: "Jêrnav", rows: 1, narrow: true, izah: "Guhandar jêrnavê heywan e" },
{ 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");
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ûneya emilandina kelîmeyê tu bi xwe binivîse…");
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îpsiyona bi alfabeya latînî")
);
}
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", "Tercimeya kurmancî")
);
}
if (subWrap.children().length) li.append(subWrap);
return li;
}
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");
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 + ": " + g.izah);
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 — a growing list, sibling to Nimûne —
// Structured the same way as Nimûne (ol.wiktku-dfn-sublist > li) so it
// lines up at the same indentation, and so that typing into the last
// citation's Jêgirtin box automatically opens a fresh empty one below it.
(function () {
var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group");
var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel").text("Jêgirtin: ");
var jederList = $("<ol></ol>").addClass("wiktku-dfn-sublist wiktku-dfn-jeder-list");
function buildJederLi() {
var lang = getValues().lang || "";
var li = $("<li></li>").addClass("wiktku-dfn-jeder-li");
// 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", "Nimûneya emilandinê ji kitêb an çavkaniyeke din binivîse");
quoteTa.on("input", function () {
var val = $.trim($(this).val());
var isLast = li.is(jederList.children("li:last-child"));
if (val && isLast) {
jederList.append(buildJederLi());
}
});
li.append(quoteTa);
// tr/t sub-fields for the quote — shown as needed for the language.
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ê bi kurmancî")
);
}
if (quoteSubWrap.children().length) li.append(quoteSubWrap);
// Source template selector, specific to this citation.
var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel");
srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>"));
srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim"));
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;
if (chosen === "__manual__") {
// Freeform source, written by the user — becomes the 2nd
// positional param of {{jêder|lang|…}} instead of çavkanî?.
srcFields.append(
$("<textarea></textarea>")
.attr("rows", 4)
.addClass("wiktku-dfn-subfield wiktku-dfn-quote-src-manual")
.attr("placeholder", "Çavkaniyê bi destê xwe binivîse…")
);
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);
});
});
li.append(srcSel).append(srcFields);
return li;
}
jederGroupDiv.data("buildJederLi", buildJederLi);
jederList.append(buildJederLi());
jederGroupDiv.append(jederLbl).append(jederList);
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;
}
// Jêder is a growing list of citations, one per li — mirrors readNimuneList().
function readJederList() {
var items = [];
block.find(".wiktku-dfn-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
var quote = $.trim(li.find(".wiktku-dfn-nimune-quote").val());
if (!quote) return;
var obj = { quote: quote };
var qtr = $.trim(li.find(".wiktku-dfn-nimune-quote-tr").val());
var qt = $.trim(li.find(".wiktku-dfn-nimune-quote-t").val());
if (qtr) obj.quoteTr = qtr;
if (qt) obj.quoteT = qt;
var tplName = li.find(".wiktku-dfn-quote-src-sel").val();
if (tplName === "__manual__") {
var manual = $.trim(li.find(".wiktku-dfn-quote-src-manual").val());
if (manual) obj.jederManual = manual;
} else if (tplName) {
obj.jederTpl = tplName;
var fields = {};
li.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(),
jeder: readJederList(),
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("koordîne", sense.koordine);
out += wordLine("jornav", sense.jornav);
out += wordLine("jêrnav", sense.jernav);
// Nimûne lines — always last, unless a jêder citation already covers it.
var hasJeder = sense.jeder && $.grep(sense.jeder, function (j) {
return j && j.quote;
}).length > 0;
out += formatNimune(sense.nimune, lang, hasJeder);
// 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", "Nimûne: Ji {{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(/CODE/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";
}
// 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";
} },
dunde: {
id: "dunde",
name: "dûnde",
visible: function (values) {
return !!values.pos;
},
disabledKeys: {
"navz": true},
/**
* Builds one row: a language dropdown + a growing list of word
* inputs. When the dropdown gets a value the next empty row is
* appended automatically. Mirrors steps.trans's row widget, but
* flat (one shared list — dûnde isn't tied to individual senses).
*/
buildRow: function (stepDiv) {
var row = $("<li class='wiktku-dunde-row wiktku-lang-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î lê bigere");
populateMenus(langSel, steps.dunde.keys || [], steps.dunde.disabledKeys);
// When a language is chosen, ensure a next empty row exists.
langSel.on("change", function () {
steps.dunde.onLangChange(stepDiv, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-dunde-words wiktku-lang-row-words'></ul>");
var firstWord = steps.dunde.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-dunde-word-" + $.now() + "-" + Math.random().toString(36).substr(2, 9))
.attr("rows", 1)
.attr("class", "wiktku-dfn-subfield wiktku-start-narrow")
.attr("placeholder", "Kelîme…");
input.on("input", function () {
var list = $(this).closest("ul.wiktku-dunde-words");
var item = $(this).parent();
var val = $.trim($(this).val());
if (val && item.is(list.children("li:last-child"))) {
var next = steps.dunde.makeWordInput();
list.append($("<li></li>").append(next));
}
});
return input;
},
onLangChange: function (stepDiv, row) {
var list = stepDiv.find("ul.wiktku-dunde-list");
var isLast = row.is(list.children("li.wiktku-dunde-row:last-child"));
if (isLast) {
var newRow = steps.dunde.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.dunde.syncDisabledKeys(stepDiv);
},
/** Disables already-selected languages in all other dropdowns. */
syncDisabledKeys: function (stepDiv) {
var taken = $.extend({}, steps.dunde.disabledKeys);
stepDiv.find("li.wiktku-dunde-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
stepDiv.find("li.wiktku-dunde-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-dunde-list").length) return null;
var list = $("<ul class='wiktku-dunde-list wiktku-lang-row-list'></ul>");
list.append(steps.dunde.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 [langcode, words[]] rows from the DOM. */
getRows: function (stepDiv) {
var result = [];
stepDiv.find("li.wiktku-dunde-row").each(function () {
var lang = $(this).find("select").val();
if (!lang) return;
var words = [];
$(this).find("ul.wiktku-dunde-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) {
var stepDiv = $("#wiktku-start-dunde");
var rows = steps.dunde.getRows(stepDiv);
if (!rows.length) return "";
// {{dû}} accepts multiple words — one bullet per language,
// with all of that language's words piped into the same call.
var lines = $.map(rows, function (row) {
var lang = row[0], words = row[1];
return "* {{dû|" + lang + "|" + words.join("|") + "}}";
});
if (!lines.length) return "";
return "\n==== Dûnde ====\n" + lines.join("\n") + "\n";
}
},
trans: {
id: "trans",
name: "werger",
visible: function (values) {
if (!(values.lang === "ku" && values.pos)) return false;
// Hide Werger only when EVERY sense is a template sense (Guharto etc.)
// with a title filled in — i.e. there is real content but no plain
// gloss to attach a translation table to. A mix of real + template
// senses still shows Werger; the template senses are simply skipped
// in output().
//
// When nothing has been filled in at all, output() will emit
// {{mane?|lang}} instead of a gloss — but Werger should still show,
// since the user may want to add translations before they've
// settled on a gloss.
var hasRealSense = false;
var hasFilledTplSense = false;
$("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () {
var isTpl = !!$(this).find("select.wiktku-dfn-tpl-select").val();
var tplTitleVal = $.trim($(this).find("input.wiktku-dfn-tpl-title").val());
var maneVal = $.trim($(this).find("textarea.wiktku-dfn-mane").val());
if (!isTpl && maneVal) {
hasRealSense = true;
return false; // break
}
if (isTpl && tplTitleVal) {
hasFilledTplSense = true;
}
});
return hasRealSense || !hasFilledTplSense;
},
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.
*
* @param group the specific .wiktku-trans-group this row belongs to
* (each gloss has its own group and its own list of rows, so the
* lookups below must stay scoped to that group rather than the
* whole step — the step now holds one list per gloss).
*/
buildRow: function (group) {
var row = $("<li class='wiktku-trans-row wiktku-lang-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î lê bigere");
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(group, row);
});
// Word list for this language.
var wordList = $("<ul class='wiktku-trans-words wiktku-lang-row-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 (group, row) {
var list = group.find("ul.wiktku-trans-list");
var isLast = row.is(list.children("li.wiktku-trans-row:last-child"));
if (isLast) {
var newRow = steps.trans.buildRow(group);
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 this gloss's lang selectors
// only — the same language can be used for different senses.
steps.trans.syncDisabledKeys(group);
},
/** Disables already-selected languages in all other dropdowns within one group. */
syncDisabledKeys: function (group) {
var taken = $.extend({}, steps.trans.disabledKeys);
group.find("li.wiktku-trans-row select").each(function () {
var v = $(this).val();
if (v) taken[v] = true;
});
group.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");
});
},
/**
* Builds (or fetches) the .wiktku-trans-group for one gloss, with
* its own label and its own list of translation rows.
*/
buildGroup: function (stepDiv, gi) {
var group = $("<div class='wiktku-trans-group'></div>").attr("data-gloss-pos", gi);
var list = $("<ul class='wiktku-trans-list wiktku-lang-row-list'></ul>");
list.append(steps.trans.buildRow(group));
group.append(list);
stepDiv.append(group);
// Init chosen after the select is in the DOM (desktop only).
if (!isMobile) list.find("select").chosen(chosenOptions);
return group;
},
/**
* Syncs one .wiktku-trans-group per current gloss, adding new
* groups and removing stale ones as senses are added or removed,
* while leaving existing groups (and whatever translations the
* user has already typed into them) untouched. Groups are keyed
* to their gloss's position in glossList() via data-gloss-pos, so
* a group always matches the same sense across rebuilds as long
* as senses aren't reordered relative to each other.
*/
build: function (stepDiv) {
var glosses = steps.trans.glossList();
if (!glosses.length) {
stepDiv.find(".wiktku-trans-group").remove();
return null;
}
// Drop groups for glosses that no longer exist (always from the
// tail — groups are only ever appended in gloss order below).
var existingGroups = stepDiv.find(".wiktku-trans-group");
if (existingGroups.length > glosses.length) {
existingGroups.slice(glosses.length).remove();
}
$.each(glosses, function (gi, gloss) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) group = steps.trans.buildGroup(stepDiv, gi);
// Only label groups when there's more than one gloss to
// distinguish between — a single gloss needs no caption.
var label = group.find(".wiktku-trans-group-label");
if (glosses.length > 1) {
if (!label.length) {
label = $("<div class='wiktku-trans-group-label'></div>");
group.prepend(label);
}
label.text(gloss.index + " " + gloss.text);
} else if (label.length) {
label.remove();
}
});
return null;
},
/** Reads the translation rows for a single gloss group. */
getGroupTranslations: function (group) {
var result = [];
group.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;
},
/**
* Reads all translation rows from the DOM, grouped by gloss
* position — one array of [lang, words] rows per gloss group, in
* the same order as the .wiktku-trans-group elements.
*/
getTranslations: function (stepDiv) {
var result = [];
stepDiv.find(".wiktku-trans-group").each(function () {
result.push(steps.trans.getGroupTranslations($(this)));
});
return result;
},
/**
* Builds the numbered "{ index, gloss }" list — one entry per dfn
* sense that has a real mane (skips template senses like Guharto,
* which have nothing to caption a translation table with). The
* index matches the sense's actual position in the numbered "#"
* definition list (1-based), including template senses in the count,
* so the number printed next to {{werger-ser}} lines up with the
* gloss the reader sees in the entry.
*
* When nothing has been filled in at all (dfn.getOutput() will emit
* {{mane?|lang}} as sense 1), this returns a single placeholder
* entry with empty text instead of an empty array, so Werger still
* has one group to attach translations to before a gloss exists.
* When every filled sense is a template sense instead, this stays
* empty — that mirrors trans.visible()'s hidden case, where there's
* no group in the DOM for a placeholder to attach to anyway.
*/
glossList: function () {
var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn"));
var glosses = [];
var hasFilledTplSense = false;
$.each(dfnSenses, function (i, s) {
if (s.tpl) {
if (s.tplTitle) hasFilledTplSense = true;
return; // template sense — no gloss to caption with
}
var dfn = s.mane;
if (!dfn) return;
if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn);
if (!dfn.match(/[.…?!)\]]$/)) dfn += "";
glosses.push({ index: i + 1, text: stripWikilinks(dfn) });
});
if (!glosses.length && !hasFilledTplSense) {
glosses.push({ index: 1, text: "" });
}
return glosses;
},
output: function (values) {
if (values.lang !== "ku") return "";
var stepDiv = $("#wiktku-start-trans");
var glosses = steps.trans.glossList();
// Every sense is a template sense — there's no real gloss
// anywhere and no group in the DOM either (glossList() only
// returns empty in that case), so skip the section entirely.
if (!glosses.length) return "";
// Each gloss now has its own group of translation rows —
// attach every gloss's own words under its own werger-ser/-bin
// pair instead of dumping everything under the first one.
var blocks = $.map(glosses, function (gloss, gi) {
var group = stepDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
var rows = group.length ? steps.trans.getGroupTranslations(group) : [];
// Placeholder gloss (no real mane entered yet) with nothing
// translated into it — nothing to output, and gloss.text is
// empty so there's no caption to give {{werger-ser}} anyway.
if (!gloss.text && !rows.length) return undefined;
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");
});
}
var wordLines = $.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");
var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}";
if (wordLines) block += "\n" + wordLines;
block += "\n{{werger-bin}}";
return block;
});
if (!blocks.length) return "";
return "\n==== Werger ====\n" + blocks.join("\n") + "\n";
}
},
};
steps.trans.keys = steps.lang.choices;
steps.dunde.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.dunde, 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", "dunde", "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) entries — a growing list, restored using the
// builder just like Nimûne. Accepts either the current array shape or a
// single legacy object (from older saved sections) for backwards compatibility.
var jederArr = $.isArray(sense.jeder) ? sense.jeder : (sense.jeder ? [sense.jeder] : []);
if (jederArr.length) {
var jederGroupDiv = block.find(".wiktku-dfn-jeder-group");
var jederList = jederGroupDiv.find("ol.wiktku-dfn-jeder-list");
var buildJederFn = jederGroupDiv.data("buildJederLi");
jederList.empty();
$.each(jederArr, function (_, j) {
if (!j || !j.quote) return;
var li = buildJederFn ? buildJederFn() : $("<li class='wiktku-dfn-jeder-li'></li>");
li.find(".wiktku-dfn-nimune-quote").val(j.quote);
if (j.quoteTr) li.find(".wiktku-dfn-nimune-quote-tr").val(j.quoteTr);
if (j.quoteT) li.find(".wiktku-dfn-nimune-quote-t").val(j.quoteT);
if (j.jederManual) {
var manualSel = li.find(".wiktku-dfn-quote-src-sel");
manualSel.val("__manual__").trigger("change");
li.find(".wiktku-dfn-quote-src-manual").val(j.jederManual);
} else if (j.jederTpl) {
var srcSel = li.find(".wiktku-dfn-quote-src-sel");
srcSel.val(j.jederTpl).trigger("change");
if (j.jêderFields) {
$.each(j.jêderFields, function (key, val) {
li.find(".wiktku-dfn-quote-src-input[data-field-key='" + key + "']").val(val);
});
}
}
jederList.append(li);
});
// Always leave a blank trailing item, same as Nimûne.
if (buildJederFn) jederList.append(buildJederFn());
}
});
}
/**
* 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;
}
if (id === "dunde") {
snap.dunde = steps.dunde.getRows(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 groups (dfn must already be restored by this
// point in the $.each loop, so glossList() reflects it).
var transDiv = $("#wiktku-start-trans");
transDiv.find(".wiktku-trans-group").remove();
steps.trans.build(transDiv);
var groupsSnap = snap.trans || [];
$.each(groupsSnap, function (gi, rows) {
var group = transDiv.find(".wiktku-trans-group[data-gloss-pos='" + gi + "']");
if (!group.length) return; // gloss no longer exists — drop its rows
var list = group.find("ul.wiktku-trans-list");
$.each(rows, function (j, row) {
var lang = row[0], words = row[1];
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 (k, word) {
var wordItems = wordList.find("li");
if (k < wordItems.length) {
wordItems.eq(k).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;
}
if (id === "dunde") {
// Rebuild dunde rows.
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-list").remove();
steps.dunde.build(dundeDiv);
var dundeRows = snap.dunde || [];
$.each(dundeRows, function (i, row) {
var lang = row[0], words = row[1];
var list = dundeDiv.find("ul.wiktku-dunde-list");
var lastRow = list.find("li.wiktku-dunde-row").last();
lastRow.find("select").val(lang).trigger("change");
var wordList = lastRow.find("ul.wiktku-dunde-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.dunde.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.dunde.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.dunde.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û]] v.2.0) +" +
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();
});
}());
// Sync tr/t sub-fields in every jêder citation 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-jeder-list li.wiktku-dfn-jeder-li").each(function () {
var li = $(this);
// Ensure the sub-wrapper exists when we need it. It must sit right
// after the quote textarea and before the source selector.
var subWrap = li.find(".wiktku-dfn-quote-sub");
// tr field
var trTa = li.find(".wiktku-dfn-nimune-quote-tr");
if (showTr && !trTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
trTa = $("<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ê…");
subWrap.prepend(trTa);
} else if (!showTr && trTa.length) {
trTa.remove();
}
// t field
var tTa = li.find(".wiktku-dfn-nimune-quote-t");
if (showT && !tTa.length) {
if (!subWrap.length) {
subWrap = $("<div></div>").addClass("wiktku-dfn-quote-sub");
li.find(".wiktku-dfn-nimune-quote").after(subWrap);
}
tTa = $("<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î)…");
subWrap.append(tTa);
} else if (!showT && tTa.length) {
tTa.remove();
}
// Remove the wrapper if it ended up empty.
subWrap = li.find(".wiktku-dfn-quote-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;
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(".wiktku-trans-group").remove();
return;
}
if (id === "dunde") {
var dundeDiv = $("#wiktku-start-dunde");
dundeDiv.find("ul.wiktku-dunde-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;
steps.dunde.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");
var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield");
populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde));
dundeMenus.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/dunde keys with the (now populated) lang choices.
steps.trans.keys = steps.lang.choices;
steps.dunde.keys = steps.lang.choices;
}).always(build);
});
});
//</nowiki>
kjcypk4ljd4z3ahixmt13vaw0hcrkyn
e-zine
0
976057
6241879
5087678
2026-07-12T21:26:36Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241879
wikitext
text/x-wiki
{{binêre herwiha|ezine}}
== {{ziman|en}} ==
=== Navdêr ===
{{en-navdêr}}
# {{f|en|computing}} [[magazîn|Magazîn]]eke ku di forma [[elektronîk]] de tê weşandin, xisûsen li ser [[înternet]]ê.
==== Hevmane ====
* {{g|en|cyberzine}}
* {{g|en|webmag}}
* {{g|en|webzine}}
==== Etîmolojî ====
Ji {{pêş|en|e-<id:dijîtal>|zine}}.
=== Çavkanî ===
* "[https://web.archive.org/web/20070223230018/http://www.reference.com/browse/wiki/Online_magazine online magazine]" at ''reference.com''.
* ''Oxford English Dictionary'', 2nd ed., 1989. (Draft entry, Sep., 2001.)
qu2y4mareht947b859qr5dir6ancqh7
وەیوە
0
976663
6241841
5090299
2026-07-12T17:20:55Z
Kurdanparez
14556
6241841
wikitext
text/x-wiki
== {{ziman|hac}} ==
===Bilêvkirin===
* {{hac-IPA|"weywe}}
=== Navdêr ===
{{navdêr|hac|z=m}}
# [[bûk]]
====Etîmolojî====
Hevreha {{hv|zza|veyve}}, {{hv|ku|bûk}}.
kfbnq8d91vxdrm0fw7q7wx17cha3l3y
6241842
6241841
2026-07-12T17:21:14Z
Kurdanparez
14556
6241842
wikitext
text/x-wiki
== {{ziman|hac}} ==
===Bilêvkirin===
* {{hac-IPA|"weywe}}
=== Navdêr ===
{{navdêr|hac|z=m}}
# [[bûk]]
====Etîmolojî====
Hevreha {{hv|zza|veyve}}, {{hv|ku|bûk}}.
[[Kategorî:Peyvên hewramî bi paşgira ـە (mêker)]]
s338yh5fcqidbgst637itus83ricfvl
Şablon:ISO 639
10
978473
6241907
5143776
2026-07-12T21:52:03Z
Wikihez
7344
6241907
wikitext
text/x-wiki
<includeonly><!--
-->{{#if:{{{ref|}}}<!--
-->|<!--
-->{{#if:{{{1|}}}<!--
-->|<!--
-->Koda {{w|ISO 639-1}} '''{{{1}}}'''{{#if:{{{3|{{{2|}}}}}}|, }}<!--
-->}}<!--
-->{{#if:{{{2|}}}<!--
-->|<!--
-->Koda {{w|ISO 639-2}} '''{{{2}}}''' [https://www.loc.gov/standards/iso639-2/php/code_list.php]{{#if:{{{3|}}}|, }}<!--
-->}}<!--
-->{{#if:{{{3|}}}<!--
-->|<!--
-->Koda {{w|ISO 639-3}} '''{{{3|}}}''' [https://iso639-3.sil.org/code/{{{3|}}} (SIL)]<!--
-->}}<!--
-->{{#if:{{{5|}}}<!--
-->|<!--
-->Koda {{w|ISO 639-5}} '''{{{5}}}''' [http://www.loc.gov/standards/iso639-5/id.php]<!--
-->}}<!--
-->|<!--
-->{{etîket|navz|standardên navneteweyî|{{#if:{{{obs|}}}|obsolete|{{#if:{{{hist|}}}|historical}}}}}} [[koda zimanî|Koda zimanî]] ya ''{{#if:{{{obs|}}}|Former }}{{#switch:{{{1}}}
|1={{w|ISO 639-1}}[[Category:ISO 639-1]]
|2={{w|ISO 639-2}}[[Category:ISO 639-2]]{{#if:{{{2|}}}|[[Category:Theknightwho's maintenance category]]}}
|2B={{w|ISO 639-2}}/B[[Category:ISO 639-2]]{{#if:{{{2|}}}|[[Category:Theknightwho's maintenance category]]}}
|2&3={{w|ISO 639-2}}[[Category:ISO 639-2]] & {{w|ISO 639-3}}[[Category:ISO 639-3]]{{#if:{{{2|}}}|[[Category:Theknightwho's maintenance category]]}}
|2T&3={{w|ISO 639-2}}/T[[Category:ISO 639-2]] & {{w|ISO 639-3}}[[Category:ISO 639-3]]{{#if:{{{2|}}}|[[Category:Theknightwho's maintenance category]]}}
|2&5={{w|ISO 639-2}}[[Category:ISO 639-2]] & {{w|ISO 639-5}}[[Category:ISO 639-5]]{{#if:{{{2|}}}|[[Category:Theknightwho's maintenance category]]}}
|3={{w|ISO 639-3}}[[Category:ISO 639-3]]
|5={{w|ISO 639-5}}[[Category:ISO 639-5]]
}} ji bo {{#if:{{{nolink|}}}|{{{2}}}|''{{w|ISO 639:{{PAGENAME}}|'''{{{3|{{{2|{{m+|{{PAGENAME}}|-}}}}}}}}'''{{#if:{{{dab|}}}| ({{{dab}}})}}}}''}}.''<!--
-->}}<!--
--></includeonly><!--
--><noinclude>{{belgekirin}}</noinclude>
rbl32mdaerjmc775vzze24f3xf8lt3t
Modul:înterwîkî-çêke
828
980350
6241801
6241369
2026-07-12T13:51:31Z
Wikihez
7344
6241801
Scribunto
text/plain
--Ev modul li gorî navê kategoriyekê lînka înterwîkiyê lê zêde dike. Bi şablona {{înterwîkî-çêke}} tê bikaranîn bi vî awayî {{subst:înterwîkî-çêke}}
-- [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge]] vê modulê bi kar tîne ji bo lêzêdekirina înterwîkiyê.
local k = {}
local b = require("Modul:bingeh")
local bibine = mw.ustring.find
local m_languages = "Modul:languages"
local m_families = "Modul:families"
local daneTerms = {
{"compound terms", ".*pêkhatî$"},
{"multiword terms", ".*hevedudanî$"},
}
local daneTermsBi = {
{"terms with usage examples", "Nimûne.*"},
{"terms with audio links", "Deng bi.*"},
{"terms with IPA pronunciation", "Bilêvkirina IPAyê.*"},
{"terms with unknown etymologies", "Etîmolojî nayê zanîn.*"},
{"terms with unknown homophones", "Hevdeng.*"},
{"terms with unknown quotations", "Jêgirtin.*"},
{"terms by etymology", "Etîmolojî.*"},
{"doublets", "Cotreh.*"},
{"internationalisms", "Navneteweyîtî.*"},
{"clippings", "Qusandin.*"},
{"calques", "Wergerandinên yekser.*"},
{"term requests", "Daxwazên peyvan.*"},
{"compound terms", ".*pêkhatî.*"},
{"puristic terms", "Pûrizm.*"},
{"dialectal terms", "Devokî.*"},
{"metonyms", "Metonîm.*"},
}
local daneDawi = {
{"Requests concerning", "Gotarên bi şaşî û kêmasî.*"},
}
local daneKodDawi = {
{"Terms with redundant transliterations", "Transliterasyona nepêwîst.*"},
}
local daneZterms = {
{"Requests for native script for", "Daxwazên skrîpta peyvê.*"},
}
local function getObj(name, family)
if not family then
return require(m_languages).getByCanonicalName(name)
or require(m_languages).getByCanonicalName(name, nil, "allowetym")
else
return require(m_families).getByCanonicalName(name)
end
end
function k.ziman_en(kod)
return mw.getCurrentFrame():expandTemplate{title = "navê zimanî/en", args = {kod}}
end
function k.get_rezimani(label)
local m_labeldataRezimani = mw.loadData("Modul:dara kategoriyan/ferhengokkatbike/dane/rêzimanî")
-- Added .interwiki[1] to get the actual text
if m_labeldataRezimani[label] and m_labeldataRezimani[label].interwiki then
return m_labeldataRezimani[label].interwiki[1]
else
return nil
end
end
function k.get_label_info(label)
local m_labeldata = mw.loadData("Modul:dara kategoriyan/ferhengokkatbike/dane/ferhengok")
-- Added .interwiki[1] to get the actual text
if m_labeldata[label] and m_labeldata[label].interwiki then
return m_labeldata[label].interwiki[1]
else
return nil
end
end
function k.get_mane(label)
local m_labeldata = mw.loadData("Modul:dara kategoriyan/ferhengokkatbike/dane/mane")
-- Added .interwiki[1] to get the actual text
if m_labeldata[label] and m_labeldata[label].interwiki then
return m_labeldata[label].interwiki[1]
else
return nil
end
end
local function splitLabelLang(rupel)
local getByCanonicalName = require(m_languages).getByCanonicalName
local canonicalName
local lang
-- Progressively add another word to the potential canonical name until it
-- matches an actual canonical name.
local words = mw.text.split(rupel, " ")
for i = #words - 1, 1, -1 do
canonicalName = table.concat(words, " ", 1, i)
lang = getByCanonicalName(canonicalName)
if lang then
break
end
end
local label = lang and rupel:sub(#canonicalName + 2)
or rupel
return label, lang
end
function k.interwiki_ceke(rupel)
-- terms
for _, terms_regex in ipairs(daneTerms) do
local terms, regex = unpack(terms_regex)
if bibine(rupel, regex) then
local ziman = rupel:match("Peyvên (.+) yên.+")
local enziman
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
enziman = k.ziman_en(kod)
return enziman ..' '.. terms .. ''
else
return b.ucfirst(terms) .. ' by language'
end
end
end
-- [[:Kategorî:Hemû ziman
local langName = rupel:match("^(.+)")
-- Use the entire category name if it doesn't end in "language", to handle
-- cases where "language" is part of the name, e.g. ASL.
local ziman = b.lcfirst(langName)
local lang = require("Module:ziman").getByCanonicalName(ziman) or require("Module:ziman").getByCanonicalName(rupel)
local enziman
if not lang then
local lang2 = require(m_languages).getByCanonicalName(langName)
if lang2 then
error('"' .. langName .. '" is not a valid canonical name. Use "' .. lang2:getCanonicalName() .. '" instead.')
end
else
lang = lang:getCode()
enziman = k.ziman_en(lang)
return enziman.. ' language'
end
--[[:Kategorî:Werger]]
if rupel:find("^Werger bi ") then
local langName = rupel:match("^Werger bi (.+)$")
local lang = require("Module:ziman").getByCanonicalName(langName)
lang = lang:getCode()
local Enziman = k.ziman_en(lang)
return 'Terms with ' .. Enziman .. ' translations'
end
--[[:Kategorî:Rûpelên bi madeyan]]
local hejmar = rupel:match("^Rûpelên bi (%d+) madeyan$")
if hejmar then
return 'Pages with ' .. hejmar .. ' entries'
end
--[[:Kategorî:Zimanên kreyolî yan pîdgînî]]
if rupel:find("^[zZ]imanên kreyolî yan pîdgînî li ser bingeha ") then
local kreyoliName = rupel:match("^[zZ]imanên kreyolî yan pîdgînî li ser bingeha (.+)$")
local lang = require("Module:ziman").getByCanonicalName(kreyoliName)
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. '-based creole or pidgin languages'
end
--[[:Kategorî:Ziman li gorî malbatan]]
if rupel:find("^[zZ]imanên") then
local familyName = rupel:match("^[zZ]imanên (.+)$")
local family = require("Module:malbat").getByCanonicalName(familyName) or
require("Module:malbat").getByCanonicalName(mw.ustring.lower(familyName))
local malbat = family:getCode()
local malbatKod = require("Module:malbat").getByCodeEn(malbat)
return '' .. malbatKod:getCanonicalName() .. ' languages'
end
-- [[Modul:dara kategoriyan/rehkatbike]]
local label, lang = splitLabelLang(rupel)
if label:find("^.+ ji rehê .") then
local ziman, after = label:match("Peyvên (.+) ji rehê (.+)$")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
end
local term, id
if after:find(". %([^()]+%)$") then
term, id = after:match("^(.+) %(([^()]+)%)$")
else
term = after
end
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. ' terms belonging to the root ' .. term .. ''
end
local label, lang = splitLabelLang(rupel)
for _, affixtype in ipairs({"circumfix", "rehan", "navgir", "pêşgir", "paşgir"}) do
if label:find("^Peyvên.+ li gorî ".. affixtype ..'an') then
local ziman = label:match("Peyvên (.+) yên li gorî " .. affixtype .. "an")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
if affixtype == "navgir" then
affixtype = "interfix"
elseif affixtype == "paşgir" then
affixtype = "suffix"
elseif affixtype == "pêşgir" then
affixtype = "prefix"
elseif affixtype == "reh" then
affixtype = "root"
end
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. ' terms by ' .. affixtype ..''
end
end
end
-- [[Modul:dara kategoriyan/qertafkatbike]]
local label, lang = splitLabelLang(rupel)
for _, affixtype in ipairs({"circumfix", "infix", "navgir", "pêşgir", "paşgir"}) do
if label:find("^.+ bi " .. affixtype .. "a .") then
local ziman, after = label:match("Peyvên (.+) bi " .. affixtype .. "a (.+)$")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
lang = lang:getCode()
enZiman = k.ziman_en(lang)
end
local term, id
if after:find(". %([^()]+%)$") then
term, id = after:match("^(.+) %(([^()]+)%)$")
else
term = after
end
if affixtype == "navgir" then
affixtype = "interfix"
elseif affixtype == "paşgir" then
affixtype = "suffix"
elseif affixtype == "pêşgir" then
affixtype = "prefix"
end
return '' .. enZiman .. ' terms '.. affixtype .. 'ed with ' .. term .. ''
--return {title = affixtype .. "katbike", args = {lang:getCode(), term, pos = pos, id = id}}
end
local label, lang = splitLabelLang(rupel)
if label:find("^Peyvên.+ li gorî rehan") then
local ziman = label:match("Peyvên (.+) yên li gorî rehan")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. ' terms by root'
end
end
end
local label, lang = splitLabelLang(rupel)
for _, etimtype in ipairs({"deynkirî ji", "mîrasmayî ji", "ji"}) do
if label:find("(.+) y?ê?n? ?".. etimtype .. " zimanên din") then
local ziman = label:match("Peyvên (.+) y?ê?n? ?".. etimtype .. " zimanên din$")
if ziman then
ziman = getObj(ziman)
if etimtype == "deynkirî ji" then
etimtype = "borrowed"
elseif etimtype == "mîrasmayî ji" then
etimtype = "inherited"
else
etimtype = "derived "
end
lang = ziman
lang = k.ziman_en(lang:getCode())
if etimtype == "derived " then
return ''.. lang .. ' terms derived from other languages'
else
return ''.. lang .. " " .. etimtype .. ' terms'
end
end
end
end
-- [[Modul:dara kategoriyan/deynkirîkatbike]]
local label, lang = splitLabelLang(rupel)
for _, etimtype in ipairs({"deynkirî", "mîrasmayî", "wergerandina yekser"}) do
if label:find("(.+) ".. etimtype .. " ji .") then
local navewergir, sourcename = label:match("Peyvên (.+) yên ".. etimtype .. " ji (.+)$")
local wergir
local source
if navewergir then
wergir = getObj(navewergir)
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
else
source = getObj(sourcename)
end
if etimtype == "deynkirî" then
etimtype = "borrowed"
elseif etimtype == "mîrasmayî" then
etimtype = "inherited"
elseif etimtype == "wergerandina yekser" then
etimtype = "calqued"
--[[
elseif affixtype == "lihevanîna dengî wateyî" then
affixtype = "phono-semantic matchings"
elseif affixtype == "wergirtina wateyê" then
affixtype = "semantic loans"
--]]
end
lang = wergir
lang = k.ziman_en(lang:getCode())
source = k.ziman_en(source:getCode())
return lang .. ' terms '.. etimtype .. ' from ' .. source .. ''
elseif not navewergir then
local sourcename = label:match("Peyvên ".. etimtype .. " ji (.+)$")
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
source = source:getCode()
source = require("Module:malbat").getByCodeEn(source)
source = source:getCanonicalName() .. " languages"
else
source = getObj(sourcename)
source = k.ziman_en(source:getCode())
end
if etimtype == "deynkirî" then
etimtype = "borrowed"
elseif etimtype == "mîrasmayî" then
etimtype = "inherited"
elseif etimtype == "wergerandina yekser" then
etimtype = "calqued"
--[[
elseif affixtype == "lihevanîna dengî wateyî" then
affixtype = "phono-semantic matchings"
elseif affixtype == "wergirtina wateyê" then
affixtype = "semantic loans"
--]]
end
return 'Terms '.. etimtype .. ' from ' .. source .. ' by language'
end
end
end
-- [[Modul:dara kategoriyan/jikatbike]]
local label, lang = splitLabelLang(rupel)
if label:find("(.+) ji .") then
local navewergir, sourcename = label:match("Peyvên (.+) ji (.+)$")
local wergir
local source
if navewergir then
wergir = getObj(navewergir)
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
source = source:getCode()
source = require("Module:malbat").getByCodeEn(source)
source = source:getCanonicalName() .. " languages"
else
source = getObj(sourcename)
source = k.ziman_en(source:getCode())
end
lang = wergir
lang = k.ziman_en(lang:getCode())
return ''.. lang .. ' terms derived from ' .. source .. ''
elseif not navewergir then
local sourcename = label:match("Peyvên ji (.+)$")
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
source = source:getCode()
source = require("Module:malbat").getByCodeEn(source)
source = source:getCanonicalName() .. " languages"
else
source = getObj(sourcename)
source = k.ziman_en(source:getCode())
end
return 'Terms derived from ' .. source .. ' by language'
end
end
for _, kodDawi_regex in ipairs(daneKodDawi) do
local kodDawi, regex = unpack(kodDawi_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
if kod == "navz" then
kod = "mul"
elseif kod =="ku" then
kod = "kmr"
end
return ''.. kodDawi ..'/' .. kod..' '
end
end
end
for _, zTerms_regex in ipairs(daneZterms) do
local zTerms, regex = unpack(zTerms_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
Enziman = k.ziman_en(kod)
return ''.. zTerms ..' '.. Enziman .. ' terms'
end
end
end
for _, dawi_regex in ipairs(daneDawi) do
local dawi, regex = unpack(dawi_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
Enziman = k.ziman_en(kod)
return ''.. dawi ..' '.. Enziman .. ''
end
end
end
for _, termsBi_regex in ipairs(daneTermsBi) do
local termsBi, regex = unpack(termsBi_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
Enziman = k.ziman_en(kod)
return ''.. Enziman ..' '.. termsBi .. ''
else
return '' .. b.ucfirst(termsBi) .. ' by language'
end
end
end
--[[WF:Ferhengok]]
--[[Modul:dara kategoriyan/ferhengokkatbike/dane/mane]]
--[[:Kategorî:Maneyên biçûkxer bi îngilîzî]]
-- Extract the label (mane) and the language from the title
-- Example: "Maneyên biçûkxer bi kurdî" -> label_key: biçûkxer, ziman_name: kurdî
local label_key, ziman_name = rupel:match("Maneyên (.-) bi (.*)$")
if label_key then
label_key = "maneyên " .. label_key
local mane_en = k.get_mane(label_key)
if mane_en then
local kod_obj = require("Module:ziman").getByCanonicalName(ziman_name)
if kod_obj then
local kod = kod_obj:getCode()
local Enziman = k.ziman_en(kod)
return Enziman .. ' ' .. mane_en
end
end
else
label_key = rupel:match("Maneyên (.*)$")
if label_key then
label_key = "maneyên " .. label_key
local mane_en = k.get_mane(label_key)
return b.ucfirst(mane_en) .. ' by language'
end
end
local etiket, ziman = rupel:match("^(.+) bi (.*)$")
local etiket = b.lcfirst(etiket)
local interwiki = k.get_label_info(etiket)
if interwiki then
local kod = getObj(ziman)
if kod then
kod = kod:getCode()
if kod == "navz" then
kod = "mul"
elseif kod =="ku" then
kod = "kmr"
end
return kod ..':'..b.ucfirst(interwiki).. ''
end
elseif interwiki == nil then
local etiket, ziman = rupel:match("^(.+) bi (.*)$")
local etiket = b.lcfirst(etiket)
local interwiki = k.get_rezimani(etiket)
local kod = getObj(ziman)
if kod then
kod = kod:getCode()
if kod == "navz" then
kod = "mul"
end
return k.ziman_en(kod) ..' '..b.lcfirst(interwiki).. ''
else
etiket = b.lcfirst(rupel)
interwiki = k.get_rezimani(etiket)
if interwiki then
return b.ucfirst(interwiki) .. ' by language'
else
etiket = b.lcfirst(rupel)
local interwikiFerhengok = k.get_label_info(etiket)
if interwikiFerhengok then
return b.ucfirst(interwikiFerhengok)
else
return '[[Kategorî:Xeletiyên Modul:înterwîkî-çêke]]'
end
end
end
else
return '[[Kategorî:Xeletiyên Modul:înterwîkî-çêke]]'
end
end
function k.biwesine(frame)
if mw.title.getCurrentTitle().nsText == 'Şablon' then
return '(Ev şablon tenê li ser rûpelên [[Wîkîpediya:Kategorîkirin|kategoriyan]] tê bikaranîn.)'
end
local args = frame:getParent().args
if args[1] or frame.args[1] then
-- navê kategoriya îngilîzî dide. Nimûne di kategoriya "Navdêr bi îngilîzî" dide "English nouns"
local rupel = args[1] or frame.args[1]
return k.interwiki_ceke(rupel)
else
local rupel = mw.title.getCurrentTitle().text
-- navê kategoriyê bi kar tîne û înterwîkiyê çêdike.
local interwiki = k.interwiki_ceke(rupel)
return '[[en:Category:' .. interwiki .. ']]'
end
end
return k
7r58g82kq1i7y63ztvafc3ha3rc0ez6
6241806
6241801
2026-07-12T13:57:12Z
Wikihez
7344
6241806
Scribunto
text/plain
--Ev modul li gorî navê kategoriyekê lînka înterwîkiyê lê zêde dike. Bi şablona {{înterwîkî-çêke}} tê bikaranîn bi vî awayî {{subst:înterwîkî-çêke}}
-- [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge]] vê modulê bi kar tîne ji bo lêzêdekirina înterwîkiyê.
local k = {}
local b = require("Modul:bingeh")
local bibine = mw.ustring.find
local m_languages = "Modul:languages"
local m_families = "Modul:families"
local daneTerms = {
{"compound terms", ".*pêkhatî$"},
{"multiword terms", ".*hevedudanî$"},
}
local daneTermsBi = {
{"terms with usage examples", "Nimûne.*"},
{"terms with audio links", "Deng bi.*"},
{"terms with IPA pronunciation", "Bilêvkirina IPAyê.*"},
{"terms with unknown etymologies", "Etîmolojî nayê zanîn.*"},
{"terms with unknown homophones", "Hevdeng.*"},
{"terms with unknown quotations", "Jêgirtin.*"},
{"terms by etymology", "Etîmolojî.*"},
{"doublets", "Cotreh.*"},
{"internationalisms", "Navneteweyîtî.*"},
{"clippings", "Qusandin.*"},
{"calques", "Wergerandinên yekser.*"},
{"term requests", "Daxwazên peyvan.*"},
{"compound terms", ".*pêkhatî.*"},
{"puristic terms", "Pûrizm.*"},
{"dialectal terms", "Devokî.*"},
{"metonyms", "Metonîm.*"},
}
local daneDawi = {
{"Requests concerning", "Gotarên bi şaşî û kêmasî.*"},
}
local daneKodDawi = {
{"Terms with redundant transliterations", "Transliterasyona nepêwîst.*"},
}
local daneZterms = {
{"Requests for native script for", "Daxwazên skrîpta peyvê.*"},
}
local function getObj(name, family)
if not family then
return require(m_languages).getByCanonicalName(name)
or require(m_languages).getByCanonicalName(name, nil, "allowetym")
else
return require(m_families).getByCanonicalName(name)
end
end
function k.ziman_en(kod)
return mw.getCurrentFrame():expandTemplate{title = "navê zimanî/en", args = {kod}}
end
function k.get_rezimani(label)
local m_labeldataRezimani = mw.loadData("Modul:dara kategoriyan/ferhengokkatbike/dane/rêzimanî")
-- Added .interwiki[1] to get the actual text
if m_labeldataRezimani[label] and m_labeldataRezimani[label].interwiki then
return m_labeldataRezimani[label].interwiki[1]
else
return nil
end
end
function k.get_label_info(label)
local m_labeldata = mw.loadData("Modul:dara kategoriyan/ferhengokkatbike/dane/ferhengok")
-- Added .interwiki[1] to get the actual text
if m_labeldata[label] and m_labeldata[label].interwiki then
return m_labeldata[label].interwiki[1]
else
return nil
end
end
function k.get_mane(label)
local m_labeldata = mw.loadData("Modul:dara kategoriyan/ferhengokkatbike/dane/mane")
-- Added .interwiki[1] to get the actual text
if m_labeldata[label] and m_labeldata[label].interwiki then
return m_labeldata[label].interwiki[1]
else
return nil
end
end
local function splitLabelLang(rupel)
local getByCanonicalName = require(m_languages).getByCanonicalName
local canonicalName
local lang
-- Progressively add another word to the potential canonical name until it
-- matches an actual canonical name.
local words = mw.text.split(rupel, " ")
for i = #words - 1, 1, -1 do
canonicalName = table.concat(words, " ", 1, i)
lang = getByCanonicalName(canonicalName)
if lang then
break
end
end
local label = lang and rupel:sub(#canonicalName + 2)
or rupel
return label, lang
end
function k.interwiki_ceke(rupel)
-- terms
for _, terms_regex in ipairs(daneTerms) do
local terms, regex = unpack(terms_regex)
if bibine(rupel, regex) then
local ziman = rupel:match("Peyvên (.+) yên.+")
local enziman
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
enziman = k.ziman_en(kod)
return enziman ..' '.. terms .. ''
else
return b.ucfirst(terms) .. ' by language'
end
end
end
-- [[:Kategorî:Hemû ziman
local langName = rupel:match("^(.+)")
-- Use the entire category name if it doesn't end in "language", to handle
-- cases where "language" is part of the name, e.g. ASL.
local ziman = b.lcfirst(langName)
local lang = require("Module:ziman").getByCanonicalName(ziman) or require("Module:ziman").getByCanonicalName(rupel)
local enziman
if not lang then
local lang2 = require(m_languages).getByCanonicalName(langName)
if lang2 then
error('"' .. langName .. '" is not a valid canonical name. Use "' .. lang2:getCanonicalName() .. '" instead.')
end
else
lang = lang:getCode()
enziman = k.ziman_en(lang)
return enziman.. ' language'
end
--[[:Kategorî:Werger]]
if rupel:find("^Werger bi ") then
local langName = rupel:match("^Werger bi (.+)$")
local lang = require("Module:ziman").getByCanonicalName(langName)
lang = lang:getCode()
local Enziman = k.ziman_en(lang)
return 'Terms with ' .. Enziman .. ' translations'
end
--[[:Kategorî:Rûpelên bi madeyan]]
if rupel:find("^Rûpelên bi (%d+) madeyan$") then
local hejmar = rupel:match("^Rûpelên bi (%d+) madeyan$")
if hejmar then
return 'Pages with ' .. hejmar .. ' entries'
end
end
--[[:Kategorî:Zimanên kreyolî yan pîdgînî]]
if rupel:find("^[zZ]imanên kreyolî yan pîdgînî li ser bingeha ") then
local kreyoliName = rupel:match("^[zZ]imanên kreyolî yan pîdgînî li ser bingeha (.+)$")
local lang = require("Module:ziman").getByCanonicalName(kreyoliName)
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. '-based creole or pidgin languages'
end
--[[:Kategorî:Ziman li gorî malbatan]]
if rupel:find("^[zZ]imanên") then
local familyName = rupel:match("^[zZ]imanên (.+)$")
local family = require("Module:malbat").getByCanonicalName(familyName) or
require("Module:malbat").getByCanonicalName(mw.ustring.lower(familyName))
local malbat = family:getCode()
local malbatKod = require("Module:malbat").getByCodeEn(malbat)
return '' .. malbatKod:getCanonicalName() .. ' languages'
end
-- [[Modul:dara kategoriyan/rehkatbike]]
local label, lang = splitLabelLang(rupel)
if label:find("^.+ ji rehê .") then
local ziman, after = label:match("Peyvên (.+) ji rehê (.+)$")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
end
local term, id
if after:find(". %([^()]+%)$") then
term, id = after:match("^(.+) %(([^()]+)%)$")
else
term = after
end
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. ' terms belonging to the root ' .. term .. ''
end
local label, lang = splitLabelLang(rupel)
for _, affixtype in ipairs({"circumfix", "rehan", "navgir", "pêşgir", "paşgir"}) do
if label:find("^Peyvên.+ li gorî ".. affixtype ..'an') then
local ziman = label:match("Peyvên (.+) yên li gorî " .. affixtype .. "an")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
if affixtype == "navgir" then
affixtype = "interfix"
elseif affixtype == "paşgir" then
affixtype = "suffix"
elseif affixtype == "pêşgir" then
affixtype = "prefix"
elseif affixtype == "reh" then
affixtype = "root"
end
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. ' terms by ' .. affixtype ..''
end
end
end
-- [[Modul:dara kategoriyan/qertafkatbike]]
local label, lang = splitLabelLang(rupel)
for _, affixtype in ipairs({"circumfix", "infix", "navgir", "pêşgir", "paşgir"}) do
if label:find("^.+ bi " .. affixtype .. "a .") then
local ziman, after = label:match("Peyvên (.+) bi " .. affixtype .. "a (.+)$")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
lang = lang:getCode()
enZiman = k.ziman_en(lang)
end
local term, id
if after:find(". %([^()]+%)$") then
term, id = after:match("^(.+) %(([^()]+)%)$")
else
term = after
end
if affixtype == "navgir" then
affixtype = "interfix"
elseif affixtype == "paşgir" then
affixtype = "suffix"
elseif affixtype == "pêşgir" then
affixtype = "prefix"
end
return '' .. enZiman .. ' terms '.. affixtype .. 'ed with ' .. term .. ''
--return {title = affixtype .. "katbike", args = {lang:getCode(), term, pos = pos, id = id}}
end
local label, lang = splitLabelLang(rupel)
if label:find("^Peyvên.+ li gorî rehan") then
local ziman = label:match("Peyvên (.+) yên li gorî rehan")
if ziman then
lang = require("Module:ziman").getByCanonicalName(ziman)
lang = lang:getCode()
Enziman = k.ziman_en(lang)
return '' .. Enziman .. ' terms by root'
end
end
end
local label, lang = splitLabelLang(rupel)
for _, etimtype in ipairs({"deynkirî ji", "mîrasmayî ji", "ji"}) do
if label:find("(.+) y?ê?n? ?".. etimtype .. " zimanên din") then
local ziman = label:match("Peyvên (.+) y?ê?n? ?".. etimtype .. " zimanên din$")
if ziman then
ziman = getObj(ziman)
if etimtype == "deynkirî ji" then
etimtype = "borrowed"
elseif etimtype == "mîrasmayî ji" then
etimtype = "inherited"
else
etimtype = "derived "
end
lang = ziman
lang = k.ziman_en(lang:getCode())
if etimtype == "derived " then
return ''.. lang .. ' terms derived from other languages'
else
return ''.. lang .. " " .. etimtype .. ' terms'
end
end
end
end
-- [[Modul:dara kategoriyan/deynkirîkatbike]]
local label, lang = splitLabelLang(rupel)
for _, etimtype in ipairs({"deynkirî", "mîrasmayî", "wergerandina yekser"}) do
if label:find("(.+) ".. etimtype .. " ji .") then
local navewergir, sourcename = label:match("Peyvên (.+) yên ".. etimtype .. " ji (.+)$")
local wergir
local source
if navewergir then
wergir = getObj(navewergir)
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
else
source = getObj(sourcename)
end
if etimtype == "deynkirî" then
etimtype = "borrowed"
elseif etimtype == "mîrasmayî" then
etimtype = "inherited"
elseif etimtype == "wergerandina yekser" then
etimtype = "calqued"
--[[
elseif affixtype == "lihevanîna dengî wateyî" then
affixtype = "phono-semantic matchings"
elseif affixtype == "wergirtina wateyê" then
affixtype = "semantic loans"
--]]
end
lang = wergir
lang = k.ziman_en(lang:getCode())
source = k.ziman_en(source:getCode())
return lang .. ' terms '.. etimtype .. ' from ' .. source .. ''
elseif not navewergir then
local sourcename = label:match("Peyvên ".. etimtype .. " ji (.+)$")
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
source = source:getCode()
source = require("Module:malbat").getByCodeEn(source)
source = source:getCanonicalName() .. " languages"
else
source = getObj(sourcename)
source = k.ziman_en(source:getCode())
end
if etimtype == "deynkirî" then
etimtype = "borrowed"
elseif etimtype == "mîrasmayî" then
etimtype = "inherited"
elseif etimtype == "wergerandina yekser" then
etimtype = "calqued"
--[[
elseif affixtype == "lihevanîna dengî wateyî" then
affixtype = "phono-semantic matchings"
elseif affixtype == "wergirtina wateyê" then
affixtype = "semantic loans"
--]]
end
return 'Terms '.. etimtype .. ' from ' .. source .. ' by language'
end
end
end
-- [[Modul:dara kategoriyan/jikatbike]]
local label, lang = splitLabelLang(rupel)
if label:find("(.+) ji .") then
local navewergir, sourcename = label:match("Peyvên (.+) ji (.+)$")
local wergir
local source
if navewergir then
wergir = getObj(navewergir)
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
source = source:getCode()
source = require("Module:malbat").getByCodeEn(source)
source = source:getCanonicalName() .. " languages"
else
source = getObj(sourcename)
source = k.ziman_en(source:getCode())
end
lang = wergir
lang = k.ziman_en(lang:getCode())
return ''.. lang .. ' terms derived from ' .. source .. ''
elseif not navewergir then
local sourcename = label:match("Peyvên ji (.+)$")
if sourcename:find("^zimanên ") then
sourcename = sourcename:gsub("^zimanên ", "")
source = getObj(sourcename, true)
source = source:getCode()
source = require("Module:malbat").getByCodeEn(source)
source = source:getCanonicalName() .. " languages"
else
source = getObj(sourcename)
source = k.ziman_en(source:getCode())
end
return 'Terms derived from ' .. source .. ' by language'
end
end
for _, kodDawi_regex in ipairs(daneKodDawi) do
local kodDawi, regex = unpack(kodDawi_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
if kod == "navz" then
kod = "mul"
elseif kod =="ku" then
kod = "kmr"
end
return ''.. kodDawi ..'/' .. kod..' '
end
end
end
for _, zTerms_regex in ipairs(daneZterms) do
local zTerms, regex = unpack(zTerms_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
Enziman = k.ziman_en(kod)
return ''.. zTerms ..' '.. Enziman .. ' terms'
end
end
end
for _, dawi_regex in ipairs(daneDawi) do
local dawi, regex = unpack(dawi_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
Enziman = k.ziman_en(kod)
return ''.. dawi ..' '.. Enziman .. ''
end
end
end
for _, termsBi_regex in ipairs(daneTermsBi) do
local termsBi, regex = unpack(termsBi_regex)
if bibine(rupel, regex) then
local ziman = rupel:match(".+ bi (.*)$")
local kod = require("Module:ziman").getByCanonicalName(ziman)
if kod then
kod = kod:getCode()
Enziman = k.ziman_en(kod)
return ''.. Enziman ..' '.. termsBi .. ''
else
return '' .. b.ucfirst(termsBi) .. ' by language'
end
end
end
--[[WF:Ferhengok]]
--[[Modul:dara kategoriyan/ferhengokkatbike/dane/mane]]
--[[:Kategorî:Maneyên biçûkxer bi îngilîzî]]
-- Extract the label (mane) and the language from the title
-- Example: "Maneyên biçûkxer bi kurdî" -> label_key: biçûkxer, ziman_name: kurdî
local label_key, ziman_name = rupel:match("Maneyên (.-) bi (.*)$")
if label_key then
label_key = "maneyên " .. label_key
local mane_en = k.get_mane(label_key)
if mane_en then
local kod_obj = require("Module:ziman").getByCanonicalName(ziman_name)
if kod_obj then
local kod = kod_obj:getCode()
local Enziman = k.ziman_en(kod)
return Enziman .. ' ' .. mane_en
end
end
else
label_key = rupel:match("Maneyên (.*)$")
if label_key then
label_key = "maneyên " .. label_key
local mane_en = k.get_mane(label_key)
return b.ucfirst(mane_en) .. ' by language'
end
end
local etiket, ziman = rupel:match("^(.+) bi (.*)$")
local etiket = b.lcfirst(etiket)
local interwiki = k.get_label_info(etiket)
if interwiki then
local kod = getObj(ziman)
if kod then
kod = kod:getCode()
if kod == "navz" then
kod = "mul"
elseif kod =="ku" then
kod = "kmr"
end
return kod ..':'..b.ucfirst(interwiki).. ''
end
elseif interwiki == nil then
local etiket, ziman = rupel:match("^(.+) bi (.*)$")
local etiket = b.lcfirst(etiket)
local interwiki = k.get_rezimani(etiket)
local kod = getObj(ziman)
if kod then
kod = kod:getCode()
if kod == "navz" then
kod = "mul"
end
return k.ziman_en(kod) ..' '..b.lcfirst(interwiki).. ''
else
etiket = b.lcfirst(rupel)
interwiki = k.get_rezimani(etiket)
if interwiki then
return b.ucfirst(interwiki) .. ' by language'
else
etiket = b.lcfirst(rupel)
local interwikiFerhengok = k.get_label_info(etiket)
if interwikiFerhengok then
return b.ucfirst(interwikiFerhengok)
else
return '[[Kategorî:Xeletiyên Modul:înterwîkî-çêke]]'
end
end
end
else
return '[[Kategorî:Xeletiyên Modul:înterwîkî-çêke]]'
end
end
function k.biwesine(frame)
if mw.title.getCurrentTitle().nsText == 'Şablon' then
return '(Ev şablon tenê li ser rûpelên [[Wîkîpediya:Kategorîkirin|kategoriyan]] tê bikaranîn.)'
end
local args = frame:getParent().args
if args[1] or frame.args[1] then
-- navê kategoriya îngilîzî dide. Nimûne di kategoriya "Navdêr bi îngilîzî" dide "English nouns"
local rupel = args[1] or frame.args[1]
return k.interwiki_ceke(rupel)
else
local rupel = mw.title.getCurrentTitle().text
-- navê kategoriyê bi kar tîne û înterwîkiyê çêdike.
local interwiki = k.interwiki_ceke(rupel)
return '[[en:Category:' .. interwiki .. ']]'
end
end
return k
r7d73pth3jcejba48y4hygrw1dond2f
Şablon:etîket
10
1325929
6241902
6105179
2026-07-12T21:46:47Z
Wikihez
7344
Yekkirin
6241902
wikitext
text/x-wiki
{{#invoke:labels/templates|show}}<noinclude>{{belgekirin}}</noinclude>
i3q4cre5iyzob0zm0qs4f52wxiwf9wx
6241904
6241902
2026-07-12T21:48:43Z
Wikihez
7344
Wikihezî/ê navê [[Şablon:ferhengok]] weke [[Şablon:etîket]] guhart
6241902
wikitext
text/x-wiki
{{#invoke:labels/templates|show}}<noinclude>{{belgekirin}}</noinclude>
i3q4cre5iyzob0zm0qs4f52wxiwf9wx
lighthouse
0
1356716
6241864
6230658
2026-07-12T20:44:46Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241864
wikitext
text/x-wiki
== {{ziman|en}} ==
{{wp|ziman=en}}
[[Wêne:Short lighthouse of Westkapelle.png|thumb|A lighthouse]]
[[Wêne:Roman Rock Lighthouse.webm|thumbnail|Aerial footage of a lighthouse.]]
=== Bilêvkirin ===
* {{IPA|en|/ˈlaɪthaʊs/}}
* {{deng|en|En-us-lighthouse.ogg|a=US}}
=== Navdêr ===
{{en-navdêr}}
# [[fener|Fener]], [[fanos]], [[fanos]]a [[derya]]yê, [[fener]]a [[derya]]yê. <br/>[[birc|Birc]] an [[avahî|avahiyek]] din ku [[çira]]yek tê de heye da ku [[keştî|keştiyan]] li [[derya]]yê [[hişyar kirin|hişyar bike]] an [[rêberî]] bike.
#: {{herwiha-rêz|en|light house}}
#: {{hevmaneyên peyvê|en|obeliscolychny<qq:nadir>|phare#Noun}}
#: {{hîpernîm|en|house#Noun|building#Noun|light<id:source of illumination>|;|aid#Noun}}
#: {{termên koordîne|en|light buoy#Noun|lightboat#Noun|lightship#Noun|lightvessel#Noun}}
==== Jê ====
{{col|en|lighthousekeeper|lighthouselike|lighthouseman
|lighthouse coffeepot|lighthouse keeper|lighthouse tube|screw-pile lighthouse}}
==== Etîmolojî ====
Ji {{pêk|en|light|house}}.
==== Binêre herwiha ====
* {{g|en|beacon}}
==== Anagram ====
* {{anagram|en|a=eghhilostu|houselight}}
iiodw77zeh3lhyxmnuif7u2u8d5zd05
MediaWiki:Gadget-start.js/data.json
8
1357737
6241852
6241748
2026-07-12T18:56:59Z
Wikihez
7344
6241852
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|CODE|he|ce|ki|rin}}"
},
{
"name": "IPA",
"desc": "Alfabeya fonetîk a navmiletî (IPA)",
"snippet": "{{IPA|CODE|/…/}}"
},
{
"name": "hevdeng",
"desc": "Hevdeng — gotinên bi heman dengî",
"snippet": "{{hevdeng|CODE|…}}"
}
],
"etymTpls": [
{
"name": "ji",
"desc": "Ji zimanekî din hatiye — {{ji|sourcelang|lang|kelîme|tr=|t=}}",
"snippet": "{{ji|SOURCELANG|CODE|…}}"
},
{
"name": "qertaf",
"desc": "Peyvên pêkhatî — {{qertaf|lang|pêşgir|reh}}",
"snippet": "{{qertaf|CODE|…|…}}"
},
{
"name": "q",
"desc": "Referans bo rûpelekê — {{q|lang|title}}",
"snippet": "{{q|CODE|…}}"
},
{
"name": "hv",
"desc": "Hevreh — {{hv|lang|kelîme}}",
"snippet": "{{hv|CODE|…}}"
},
{
"name": "nh",
"desc": "Nehevreh — {{nh|lang|kelîme}}",
"snippet": "{{hv|CODE|…}}"
},
{
"name": "mîr",
"desc": "Mîras (inherited) — {{mîr|lang|kelîme}}",
"snippet": "{{mîr|SOURCELANG|CODE|…}}"
},
{
"name": "deyn",
"desc": "Deyn (borrowed) — {{deyn|lang|kelîme}}",
"snippet": "{{deyn|SOURCELANG|CODE|…}}"
}
],
"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
}
}
}
3myw772grr1q5hayvb9h4zzzpwdrag6
bursiyer
0
1357743
6241779
6241722
2026-07-12T13:06:37Z
Wikihez
7344
/* Navdêr */
6241779
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}}
==== Herwiha ====
* {{hw|ku|bûrsiyer}}
==== 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}}
l1m0qu621bnht6slrwl057b1bws4ytg
Gotûbêja bikarhêner:Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
3
1357746
6241754
6241751
2026-07-12T12:04:30Z
Wikihez
7344
/* Xêrhatin */ Bersiv
6241754
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)
:::Ne muhîm e, mala te ava, Qewet be! [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 12:04, 12 tîrmeh 2026 (UTC)
m2pbcyqgl7sficxfej5j49v2f59d8pa
Tewandin:dêran
106
1357747
6241753
2026-07-12T12:01:11Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
Min agahî zêde kirin li gotarê
6241753
wikitext
text/x-wiki
==== 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
|}
7n2qzg9021aesqbaceebcbjmnls95zu
6241755
6241753
2026-07-12T12:06:46Z
Renamed user 4ec0bf0d9cf7d3fb43e75fd4ec030357
15130
/* kêşana lêkerê(conjugation) */ Min lê zêde kir
6241755
wikitext
text/x-wiki
==== kêşana lêkerê(conjugation) ====
===== 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
|}
8913fhx7s4qxu66w73uj5dkqtrpuhsg
boursier
0
1357748
6241777
2026-07-12T13:03:58Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +fr:navdêr:bursiyer
6241777
wikitext
text/x-wiki
== {{ziman|fr}} ==
=== Navdêr ===
{{navdêr|fr|c=n}}
# [[bursiyer|Bursiyer]].
#* {{bênimûne|fr}}
==== Etîmolojî ====
Ji {{qertaf|fr|bourse|-ier}}.
nyzwv0uwcqgr42q6wsr8igwp592y3dg
Kategorî:Peyvên fransî bi paşgira -ier
14
1357749
6241778
2026-07-12T13:05:07Z
Wikihez
7344
Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} û înterwîkî
6241778
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
bûrsiyer
0
1357750
6241780
2026-07-12T13:07:36Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +ku:navdêr:
6241780
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|bûrsiyer|mê û nêr}}
{{navdêr|ku|c=mn}}
# {{guharto|ku|bursiyer}}
oroojhyl79a7w989rflfv5c36rzk9js
Kategorî:Rûpelên bi 4 madeyan
14
1357751
6241800
2026-07-12T13:45:55Z
Wikihez
7344
Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} (bêyî înterwîkî)
6241800
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
talî kirin
0
1357752
6241803
2026-07-12T13:55:56Z
~2026-39288-16
15131
Rûpel bi "== {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Lêker === {{ku-tewîn-lk|talî kirin|form=gerguhêz|niha=k|borî=kir|pêşgir=talî|valahî=erê}} {{lêker|ku|c=h-gh}} # Ji bo kesekî [[bi ser ketin|bi ser bikeve]] yan ji [[tengasî]]yekê rizgar bibe ji kesekî re tiştekî [[dan]] an [[kirin]]. [[Alî Kirin]] #: {{mînak?|ku}}" hat çêkirin
6241803
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker ===
{{ku-tewîn-lk|talî kirin|form=gerguhêz|niha=k|borî=kir|pêşgir=talî|valahî=erê}}
{{lêker|ku|c=h-gh}}
# Ji bo kesekî [[bi ser ketin|bi ser bikeve]] yan ji [[tengasî]]yekê rizgar bibe ji kesekî re tiştekî [[dan]] an [[kirin]]. [[Alî Kirin]]
#: {{mînak?|ku}}
s6yc0pykhoqr6r2epzmlap4clcfs3j4
6241805
6241803
2026-07-12T13:56:47Z
~2026-39288-16
15131
/* Lêker */
6241805
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-IPA}}
* {{ku-kîte}}
=== Lêker ===
{{ku-tewîn-lk|talî kirin|form=gerguhêz|niha=k|borî=kir|pêşgir=talî|valahî=erê}}
{{lêker|ku|c=h-gh}}
# Ji bo kesekî [[bi ser ketin|bi ser bikeve]] yan ji [[tengasî]]yekê rizgar bibe ji kesekî re tiştekî [[dan]] an [[kirin]], [[alî kirin]]
#: {{mînak?|ku}}
3hrcbmftbwq1j18kv8ogv8694diycri
Modul:hac-IPA
828
1357753
6241818
2026-07-12T15:36:36Z
Kurdanparez
14556
Hawramî IPA
6241818
Scribunto
text/plain
-- Module:hac-IPA
-- Converts a Latin transliteration of Hawrami into IPA for {{hac-IPA}}.
--
-- Template usage:
-- {{hac-IPA|weşî}} -> automatic stress (falls on the last syllable)
-- {{hac-IPA|"weşî}} -> manual stress, marked with a quotation mark
-- {{hac-IPA||ˈwæʃiː}} -> manual IPA override (2nd parameter wins outright)
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. CHARACTER TABLES
--------------------------------------------------------------------------
-- Digraphs, checked before single letters.
local DIGRAPHS = {
["xw"] = "Ꭓ", -- x with superscript w
["rr"] = "Ꮢ", -- strong / trilled r
["ll"] = "Ꮮ", -- velarized / geminate l
}
-- Single letters.
local SINGLES = {
-- vowels
["a"] = "ɑː", ["e"] = "æ", ["é"] = "ɛ", ["ê"] = "eː",
["i"] = "ɘ", ["î"] = "iː", ["o"] = "oː", ["u"] = "ʊ", ["û"] = "uː",
-- consonants
["b"] = "b", ["c"] = "d͡ʒ", ["ç"] = "t͡ʃ", ["d"] = "d", ["f"] = "f",
["g"] = "ɡ", ["h"] = "h", ["j"] = "ʒ", ["k"] = "k", ["l"] = "l",
["m"] = "m", ["n"] = "n", ["p"] = "p", ["q"] = "q", ["r"] = "ɾ",
["s"] = "s", ["ş"] = "ʃ", ["t"] = "t", ["v"] = "v", ["w"] = "w",
["x"] = "x", ["y"] = "j", ["z"] = "z",
["ẍ"] = "ɣ", ["ḧ"] = "ħ", ["ʿ"] = "ʕ", ["'"] = "ʕ",
["ł"] = "ɫ", ["ň"] = "ŋ", ["ř"] = "r", ["ü"] = "yː",
["ṣ"] = "sˤ", ["ṭ"] = "tˤ", ["ẓ"] = "zˤ",
}
-- Uppercase -> lowercase for the special letters (safety net alongside
-- mw.ustring.lower, whose Unicode casing tables don't always cover these).
local UPPER_TO_LOWER = {
["É"] = "é", ["Ê"] = "ê", ["Î"] = "î", ["Û"] = "û", ["Ş"] = "ş",
["Ç"] = "ç", ["Ł"] = "ł", ["Ň"] = "ň", ["Ř"] = "ř", ["Ü"] = "ü",
["Ṣ"] = "ṣ", ["Ṭ"] = "ṭ", ["Ẓ"] = "ẓ", ["Ẍ"] = "ẍ", ["Ḧ"] = "ḧ",
}
-- Input letters that count as vowels (for the context-sensitive rules).
local IS_VOWEL_LETTER = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
-- Output IPA symbols that count as syllable nuclei (for stress placement).
local IS_VOWEL_OUTPUT = {
["ɑː"] = true, ["æ"] = true, ["ɛ"] = true, ["eː"] = true, ["ɘ"] = true,
["iː"] = true, ["oː"] = true, ["ʊ"] = true, ["uː"] = true, ["yː"] = true,
["ɔ"] = true,
}
local STRESS_MARK = "ˈ"
local QUOTE = '"'
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lowerHac(text)
text = u.lower(text)
local out = {}
for ch in u.gmatch(text, ".") do
out[#out + 1] = UPPER_TO_LOWER[ch] or ch
end
return table.concat(out)
end
local function splitChars(text)
local chars = {}
for ch in u.gmatch(text, ".") do
chars[#chars + 1] = ch
end
return chars
end
-- Maps one input letter to IPA, applying the context-sensitive rules:
-- (a) d -> ð after a vowel, or between r and a following vowel
-- (c) n -> ŋ before g/k
-- (d) o -> ʊ (unstressed, before another vowel)
-- (e) e -> ɔ in the -(e)we suffix, after a consonant
local function mapSingle(chars, i, suffixE)
local c = chars[i]
if c == "n" then
local nxt = chars[i + 1]
if nxt == "g" or nxt == "k" then
return "ŋ"
end
return "n"
end
if c == "d" then
local prev = chars[i - 1]
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[prev] then
return "ð"
elseif prev == "r" and IS_VOWEL_LETTER[nxt] then
return "ð"
end
return "d"
end
if c == "o" then
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[nxt] then
return "ʊ"
end
return SINGLES["o"]
end
if c == "e" and suffixE[i] then
return "ɔ"
end
return SINGLES[c] or c -- unknown characters pass through unchanged
end
-- Flags the "e" of a word-final "-ewe" (preceded by a consonant) for rule (e).
local function findSuffixE(chars)
local n = #chars
local flags = {}
if n >= 3 and chars[n - 2] == "e" and chars[n - 1] == "w" and chars[n] == "e" then
local before = chars[n - 3]
if before == nil or not IS_VOWEL_LETTER[before] then
flags[n - 2] = true
end
end
return flags
end
--------------------------------------------------------------------------
-- 3. TOKENIZER
-- Turns raw letters into IPA pieces, honoring xw/rr/ll digraphs and the
-- quotation-mark rules (separator vs. manual stress).
--------------------------------------------------------------------------
local function tokenize(word)
local chars = splitChars(word)
local n = #chars
local suffixE = findSuffixE(chars)
local tokens = {}
local stressBefore = nil
local i = 1
while i <= n do
local c1, c2, c3 = chars[i], chars[i + 1], chars[i + 2]
-- r"r, l"l, x"w -> quote forces the letters to be read individually,
-- instead of being combined into the rr/ll/xw digraph.
if c2 == QUOTE and (
(c1 == "r" and c3 == "r") or
(c1 == "l" and c3 == "l") or
(c1 == "x" and c3 == "w")
) then
tokens[#tokens + 1] = mapSingle(chars, i, suffixE)
tokens[#tokens + 1] = mapSingle(chars, i + 2, suffixE)
i = i + 3
-- plain digraphs
elseif c1 == "r" and c2 == "r" then
tokens[#tokens + 1] = DIGRAPHS["rr"]; i = i + 2
elseif c1 == "l" and c2 == "l" then
tokens[#tokens + 1] = DIGRAPHS["ll"]; i = i + 2
elseif c1 == "x" and c2 == "w" then
tokens[#tokens + 1] = DIGRAPHS["xw"]; i = i + 2
-- a bare quotation mark marks manual stress at this position
elseif c1 == QUOTE then
stressBefore = #tokens + 1
i = i + 1
else
tokens[#tokens + 1] = mapSingle(chars, i, suffixE)
i = i + 1
end
end
return tokens, stressBefore
end
-- Automatic stress: last syllable, i.e. right before the consonant cluster
-- leading into the final vowel. (Rule f)
local function placeAutoStress(tokens)
local lastVowel = nil
for idx = #tokens, 1, -1 do
if IS_VOWEL_OUTPUT[tokens[idx]] then
lastVowel = idx
break
end
end
if not lastVowel then
return tokens
end
local onset = lastVowel
local k = lastVowel - 1
while k >= 1 and not IS_VOWEL_OUTPUT[tokens[k]] do
onset = k
k = k - 1
end
table.insert(tokens, onset, STRESS_MARK)
return tokens
end
--------------------------------------------------------------------------
-- 4. WORD / PHRASE CONVERSION
--------------------------------------------------------------------------
function p._convertWord(word)
if word == "" then return "" end
local tokens, stressBefore = tokenize(word)
if stressBefore then
table.insert(tokens, stressBefore, STRESS_MARK)
else
tokens = placeAutoStress(tokens)
end
return table.concat(tokens)
end
function p._convert(text)
text = lowerHac(mw.text.trim(text))
local words = {}
for w in u.gmatch(text, "%S+") do
words[#words + 1] = p._convertWord(w)
end
return table.concat(words, " ")
end
--------------------------------------------------------------------------
-- 5. OUTPUT FORMATTING
--------------------------------------------------------------------------
local function formatOutput(ipa)
return string.format(
'<span class="IPA" title="Representation in the International Phonetic Alphabet (IPA)">[%s]</span>',
ipa
)
end
--------------------------------------------------------------------------
-- 6. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = v end
end
for k, v in pairs(frame.args) do args[k] = v end
return args
end
function p.IPA(frame)
local args = getArgs(frame)
local input = args[1]
local manual = args[2]
if manual and mw.text.trim(manual) ~= "" then
return formatOutput(mw.text.trim(manual))
end
if not input or mw.text.trim(input) == "" then
return ""
end
local ok, ipa = pcall(p._convert, input)
if not ok then
return formatOutput(input) .. "[[Category:Pages with hac-IPA errors]]"
end
return formatOutput(ipa)
end
return p
24ciajiomeygwa1gkqv8j3yg0008gn7
6241821
6241818
2026-07-12T15:47:38Z
Kurdanparez
14556
Update
6241821
Scribunto
text/plain
-- Module:hac-IPA
-- Converts a Latin transliteration of Hawrami into IPA for {{hac-IPA}}.
--
-- Template usage:
-- {{hac-IPA|weşî}} -> automatic stress (falls on the last syllable)
-- {{hac-IPA|"weşî}} -> manual stress, marked with a quotation mark
-- {{hac-IPA||ˈwæʃiː}} -> manual IPA override (2nd parameter wins outright)
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. CHARACTER TABLES
--------------------------------------------------------------------------
-- Digraphs, checked before single letters.
local DIGRAPHS = {
["xw"] = "Ꭓ", -- x with superscript w
["rr"] = "Ꮢ", -- strong / trilled r
["ll"] = "Ꮮ", -- velarized / geminate l
}
-- Single letters.
local SINGLES = {
-- vowels
["a"] = "ɑː", ["e"] = "æ", ["é"] = "ɛ", ["ê"] = "eː",
["i"] = "ɘ", ["î"] = "iː", ["o"] = "oː", ["u"] = "ʊ", ["û"] = "uː",
-- consonants
["b"] = "b", ["c"] = "d͡ʒ", ["ç"] = "t͡ʃ", ["d"] = "d", ["f"] = "f",
["g"] = "ɡ", ["h"] = "h", ["j"] = "ʒ", ["k"] = "k", ["l"] = "l",
["m"] = "m", ["n"] = "n", ["p"] = "p", ["q"] = "q", ["r"] = "ɾ",
["s"] = "s", ["ş"] = "ʃ", ["t"] = "t", ["v"] = "v", ["w"] = "w",
["x"] = "x", ["y"] = "j", ["z"] = "z",
["ẍ"] = "ɣ", ["ḧ"] = "ħ", ["ʿ"] = "ʕ", ["'"] = "ʕ",
["ł"] = "ɫ", ["ň"] = "ŋ", ["ř"] = "r", ["ü"] = "yː",
["ṣ"] = "sˤ", ["ṭ"] = "tˤ", ["ẓ"] = "zˤ",
}
-- Uppercase -> lowercase for the special letters (safety net alongside
-- mw.ustring.lower, whose Unicode casing tables don't always cover these).
local UPPER_TO_LOWER = {
["É"] = "é", ["Ê"] = "ê", ["Î"] = "î", ["Û"] = "û", ["Ş"] = "ş",
["Ç"] = "ç", ["Ł"] = "ł", ["Ň"] = "ň", ["Ř"] = "ř", ["Ü"] = "ü",
["Ṣ"] = "ṣ", ["Ṭ"] = "ṭ", ["Ẓ"] = "ẓ", ["Ẍ"] = "ẍ", ["Ḧ"] = "ḧ",
}
-- Input letters that count as vowels (for the context-sensitive rules).
local IS_VOWEL_LETTER = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
-- Output IPA symbols that count as syllable nuclei (for stress placement).
local IS_VOWEL_OUTPUT = {
["ɑː"] = true, ["æ"] = true, ["ɛ"] = true, ["eː"] = true, ["ɘ"] = true,
["iː"] = true, ["oː"] = true, ["ʊ"] = true, ["uː"] = true, ["yː"] = true,
["ɔ"] = true,
}
local STRESS_MARK = "ˈ"
local QUOTE = '"'
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lowerHac(text)
text = u.lower(text)
local out = {}
for ch in u.gmatch(text, ".") do
out[#out + 1] = UPPER_TO_LOWER[ch] or ch
end
return table.concat(out)
end
local function splitChars(text)
local chars = {}
for ch in u.gmatch(text, ".") do
chars[#chars + 1] = ch
end
return chars
end
-- Maps one input letter to IPA, applying the context-sensitive rules:
-- (a) d -> ð after a vowel, or between r and a following vowel
-- (c) n -> ŋ before g/k
-- (d) o -> ʊ (unstressed, before another vowel)
-- (e) e -> ɔ in the -(e)we suffix, after a consonant
local function mapSingle(chars, i, suffixE)
local c = chars[i]
if c == "n" then
local nxt = chars[i + 1]
if nxt == "g" or nxt == "k" then
return "ŋ"
end
return "n"
end
if c == "d" then
local prev = chars[i - 1]
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[prev] then
return "ð"
elseif prev == "r" and IS_VOWEL_LETTER[nxt] then
return "ð"
end
return "d"
end
if c == "o" then
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[nxt] then
return "ʊ"
end
return SINGLES["o"]
end
if c == "e" and suffixE[i] then
return "ɔ"
end
return SINGLES[c] or c -- unknown characters pass through unchanged
end
-- Flags the "e" of a word-final "-ewe" (preceded by a consonant) for rule (e).
--------------------------------------------------------------------------
-- 2. HELPERS (updated)
--------------------------------------------------------------------------
-- Detects a word-final -(e)we suffix that should be realized as a single
-- [ɔ], per rule (e):
-- • "...Cewe" (e preceded by a consonant) -> "ewe" (3 letters) = ɔ
-- • "...{i/î/u/û}we" (we preceded by i/î/u/û) -> "we" (2 letters) = ɔ
-- Returns {start = <index of first letter of suffix>, len = 2 or 3}, or nil.
local function findWeSuffix(chars)
local n = #chars
if n >= 2 and chars[n - 1] == "w" and chars[n] == "e" then
-- Case 1: "...ewe" — the e right before "we" must follow a consonant.
if n >= 3 and chars[n - 2] == "e" then
local prev = chars[n - 3]
if prev == nil or not IS_VOWEL_LETTER[prev] then
return { start = n - 2, len = 3 }
end
end
-- Case 2: "...iwe / îwe / uwe / ûwe" — bare "we" after i/î/u/û.
local prev = chars[n - 2]
if prev == "i" or prev == "î" or prev == "u" or prev == "û" then
return { start = n - 1, len = 2 }
end
end
return nil
end
-- Maps one input letter to IPA, applying the context-sensitive rules:
-- (a) d -> ð after a vowel, or between r and a following vowel
-- (c) n -> ŋ before g/k
-- (d) o -> ʊ (unstressed, before another vowel)
-- (rule (e) is now handled separately in tokenize(), as a whole-suffix swap)
local function mapSingle(chars, i)
local c = chars[i]
if c == "n" then
local nxt = chars[i + 1]
if nxt == "g" or nxt == "k" then
return "ŋ"
end
return "n"
end
if c == "d" then
local prev = chars[i - 1]
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[prev] then
return "ð"
elseif prev == "r" and IS_VOWEL_LETTER[nxt] then
return "ð"
end
return "d"
end
if c == "o" then
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[nxt] then
return "ʊ"
end
return SINGLES["o"]
end
return SINGLES[c] or c -- unknown characters pass through unchanged
end
--------------------------------------------------------------------------
-- 3. TOKENIZER (updated)
--------------------------------------------------------------------------
local function tokenize(word)
local chars = splitChars(word)
local n = #chars
local weSuffix = findWeSuffix(chars)
local tokens = {}
local stressBefore = nil
local i = 1
while i <= n do
local c1, c2, c3 = chars[i], chars[i + 1], chars[i + 2]
-- Whole -(e)we / -we suffix -> single [ɔ] (rule e).
if weSuffix and i == weSuffix.start then
tokens[#tokens + 1] = "ɔ"
i = i + weSuffix.len
-- r"r, l"l, x"w -> quote forces the letters to be read individually,
-- instead of being combined into the rr/ll/xw digraph.
elseif c2 == QUOTE and (
(c1 == "r" and c3 == "r") or
(c1 == "l" and c3 == "l") or
(c1 == "x" and c3 == "w")
) then
tokens[#tokens + 1] = mapSingle(chars, i)
tokens[#tokens + 1] = mapSingle(chars, i + 2)
i = i + 3
-- plain digraphs
elseif c1 == "r" and c2 == "r" then
tokens[#tokens + 1] = DIGRAPHS["rr"]; i = i + 2
elseif c1 == "l" and c2 == "l" then
tokens[#tokens + 1] = DIGRAPHS["ll"]; i = i + 2
elseif c1 == "x" and c2 == "w" then
tokens[#tokens + 1] = DIGRAPHS["xw"]; i = i + 2
-- a bare quotation mark marks manual stress at this position
elseif c1 == QUOTE then
stressBefore = #tokens + 1
i = i + 1
else
tokens[#tokens + 1] = mapSingle(chars, i)
i = i + 1
end
end
return tokens, stressBefore
end
--------------------------------------------------------------------------
-- 4. WORD / PHRASE CONVERSION
--------------------------------------------------------------------------
function p._convertWord(word)
if word == "" then return "" end
local tokens, stressBefore = tokenize(word)
if stressBefore then
table.insert(tokens, stressBefore, STRESS_MARK)
else
tokens = placeAutoStress(tokens)
end
return table.concat(tokens)
end
function p._convert(text)
text = lowerHac(mw.text.trim(text))
local words = {}
for w in u.gmatch(text, "%S+") do
words[#words + 1] = p._convertWord(w)
end
return table.concat(words, " ")
end
--------------------------------------------------------------------------
-- 5. OUTPUT FORMATTING
--------------------------------------------------------------------------
local function formatOutput(ipa)
return string.format(
'<span class="IPA" title="Representation in the International Phonetic Alphabet (IPA)">[%s]</span>',
ipa
)
end
--------------------------------------------------------------------------
-- 6. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = v end
end
for k, v in pairs(frame.args) do args[k] = v end
return args
end
function p.IPA(frame)
local args = getArgs(frame)
local input = args[1]
local manual = args[2]
if manual and mw.text.trim(manual) ~= "" then
return formatOutput(mw.text.trim(manual))
end
if not input or mw.text.trim(input) == "" then
return ""
end
local ok, ipa = pcall(p._convert, input)
if not ok then
return formatOutput(input) .. "[[Category:Pages with hac-IPA errors]]"
end
return formatOutput(ipa)
end
return p
doqjhe4u3gij6ectwpgz3whqtsshs6h
6241822
6241821
2026-07-12T15:49:52Z
Kurdanparez
14556
update
6241822
Scribunto
text/plain
-- Converts a Latin transliteration of Hawrami into IPA for {{hac-IPA}}.
--
-- Template usage:
-- {{hac-IPA|weşî}} -> automatic stress (falls on the last syllable)
-- {{hac-IPA|"weşî}} -> manual stress, marked with a quotation mark
-- {{hac-IPA||ˈwæʃiː}} -> manual IPA override (2nd parameter wins outright)
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. CHARACTER TABLES
--------------------------------------------------------------------------
local DIGRAPHS = {
["xw"] = "Ꭓ",
["rr"] = "Ꮢ",
["ll"] = "Ꮮ",
}
local SINGLES = {
["a"] = "ɑː", ["e"] = "æ", ["é"] = "ɛ", ["ê"] = "eː",
["i"] = "ɘ", ["î"] = "iː", ["o"] = "oː", ["u"] = "ʊ", ["û"] = "uː",
["b"] = "b", ["c"] = "d͡ʒ", ["ç"] = "t͡ʃ", ["d"] = "d", ["f"] = "f",
["g"] = "ɡ", ["h"] = "h", ["j"] = "ʒ", ["k"] = "k", ["l"] = "l",
["m"] = "m", ["n"] = "n", ["p"] = "p", ["q"] = "q", ["r"] = "ɾ",
["s"] = "s", ["ş"] = "ʃ", ["t"] = "t", ["v"] = "v", ["w"] = "w",
["x"] = "x", ["y"] = "j", ["z"] = "z",
["ẍ"] = "ɣ", ["ḧ"] = "ħ", ["ʿ"] = "ʕ", ["'"] = "ʕ",
["ł"] = "ɫ", ["ň"] = "ŋ", ["ř"] = "r", ["ü"] = "yː",
["ṣ"] = "sˤ", ["ṭ"] = "tˤ", ["ẓ"] = "zˤ",
}
local UPPER_TO_LOWER = {
["É"] = "é", ["Ê"] = "ê", ["Î"] = "î", ["Û"] = "û", ["Ş"] = "ş",
["Ç"] = "ç", ["Ł"] = "ł", ["Ň"] = "ň", ["Ř"] = "ř", ["Ü"] = "ü",
["Ṣ"] = "ṣ", ["Ṭ"] = "ṭ", ["Ẓ"] = "ẓ", ["Ẍ"] = "ẍ", ["Ḧ"] = "ḧ",
}
local IS_VOWEL_LETTER = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
local IS_VOWEL_OUTPUT = {
["ɑː"] = true, ["æ"] = true, ["ɛ"] = true, ["eː"] = true, ["ɘ"] = true,
["iː"] = true, ["oː"] = true, ["ʊ"] = true, ["uː"] = true, ["yː"] = true,
["ɔ"] = true,
}
local STRESS_MARK = "ˈ"
local QUOTE = '"'
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lowerHac(text)
text = u.lower(text)
local out = {}
for ch in u.gmatch(text, ".") do
out[#out + 1] = UPPER_TO_LOWER[ch] or ch
end
return table.concat(out)
end
local function splitChars(text)
local chars = {}
for ch in u.gmatch(text, ".") do
chars[#chars + 1] = ch
end
return chars
end
-- Detects a word-final -(e)we suffix realized as a single [ɔ] (rule e):
-- • "...Cewe" (e preceded by a consonant) -> "ewe" (3 letters)
-- • "...{i/î/u/û}we" (we preceded by i/î/u/û) -> "we" (2 letters)
local function findWeSuffix(chars)
local n = #chars
if n >= 2 and chars[n - 1] == "w" and chars[n] == "e" then
if n >= 3 and chars[n - 2] == "e" then
local prev = chars[n - 3]
if prev == nil or not IS_VOWEL_LETTER[prev] then
return { start = n - 2, len = 3 }
end
end
local prev = chars[n - 2]
if prev == "i" or prev == "î" or prev == "u" or prev == "û" then
return { start = n - 1, len = 2 }
end
end
return nil
end
-- Maps one input letter to IPA, applying context-sensitive rules:
-- (a) d -> ð after a vowel, or between r and a following vowel
-- (c) n -> ŋ before g/k
-- (d) o -> ʊ (unstressed, before another vowel)
local function mapSingle(chars, i)
local c = chars[i]
if c == "n" then
local nxt = chars[i + 1]
if nxt == "g" or nxt == "k" then
return "ŋ"
end
return "n"
end
if c == "d" then
local prev = chars[i - 1]
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[prev] then
return "ð"
elseif prev == "r" and IS_VOWEL_LETTER[nxt] then
return "ð"
end
return "d"
end
if c == "o" then
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[nxt] then
return "ʊ"
end
return SINGLES["o"]
end
return SINGLES[c] or c
end
--------------------------------------------------------------------------
-- 3. TOKENIZER
--------------------------------------------------------------------------
local function tokenize(word)
local chars = splitChars(word)
local n = #chars
local weSuffix = findWeSuffix(chars)
local tokens = {}
local stressBefore = nil
local i = 1
while i <= n do
local c1, c2, c3 = chars[i], chars[i + 1], chars[i + 2]
if weSuffix and i == weSuffix.start then
tokens[#tokens + 1] = "ɔ"
i = i + weSuffix.len
elseif c2 == QUOTE and (
(c1 == "r" and c3 == "r") or
(c1 == "l" and c3 == "l") or
(c1 == "x" and c3 == "w")
) then
tokens[#tokens + 1] = mapSingle(chars, i)
tokens[#tokens + 1] = mapSingle(chars, i + 2)
i = i + 3
elseif c1 == "r" and c2 == "r" then
tokens[#tokens + 1] = DIGRAPHS["rr"]; i = i + 2
elseif c1 == "l" and c2 == "l" then
tokens[#tokens + 1] = DIGRAPHS["ll"]; i = i + 2
elseif c1 == "x" and c2 == "w" then
tokens[#tokens + 1] = DIGRAPHS["xw"]; i = i + 2
elseif c1 == QUOTE then
stressBefore = #tokens + 1
i = i + 1
else
tokens[#tokens + 1] = mapSingle(chars, i)
i = i + 1
end
end
return tokens, stressBefore
end
-- Automatic stress: last syllable.
local function placeAutoStress(tokens)
local lastVowel = nil
for idx = #tokens, 1, -1 do
if IS_VOWEL_OUTPUT[tokens[idx]] then
lastVowel = idx
break
end
end
if not lastVowel then
return tokens
end
local onset = lastVowel
local k = lastVowel - 1
while k >= 1 and not IS_VOWEL_OUTPUT[tokens[k]] do
onset = k
k = k - 1
end
table.insert(tokens, onset, STRESS_MARK)
return tokens
end
--------------------------------------------------------------------------
-- 4. WORD / PHRASE CONVERSION
--------------------------------------------------------------------------
function p._convertWord(word)
if word == "" then return "" end
local tokens, stressBefore = tokenize(word)
if stressBefore then
table.insert(tokens, stressBefore, STRESS_MARK)
else
tokens = placeAutoStress(tokens)
end
return table.concat(tokens)
end
function p._convert(text)
text = lowerHac(mw.text.trim(text))
local words = {}
for w in u.gmatch(text, "%S+") do
words[#words + 1] = p._convertWord(w)
end
return table.concat(words, " ")
end
--------------------------------------------------------------------------
-- 5. OUTPUT FORMATTING
--------------------------------------------------------------------------
local function formatOutput(ipa)
return string.format(
'<span class="IPA" title="Representation in the International Phonetic Alphabet (IPA)">[%s]</span>',
ipa
)
end
--------------------------------------------------------------------------
-- 6. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = v end
end
for k, v in pairs(frame.args) do args[k] = v end
return args
end
function p.IPA(frame)
local args = getArgs(frame)
local input = args[1]
local manual = args[2]
if manual and mw.text.trim(manual) ~= "" then
return formatOutput(mw.text.trim(manual))
end
if not input or mw.text.trim(input) == "" then
return ""
end
local ok, ipa = pcall(p._convert, input)
if not ok then
return formatOutput(input) .. "[[Category:Pages with hac-IPA errors]]"
end
return formatOutput(ipa)
end
return p
s0k90lnizmognlqf4tei2jrsx50d0sl
6241828
6241822
2026-07-12T16:16:23Z
Kurdanparez
14556
6241828
Scribunto
text/plain
-- Converts a Latin transliteration of Hawrami into IPA for {{hac-IPA}}.
--
-- Template usage:
-- {{hac-IPA|weşî}} -> automatic stress (falls on the last syllable)
-- {{hac-IPA|"weşî}} -> manual stress, marked with a quotation mark
-- {{hac-IPA||ˈwæʃiː}} -> manual IPA override (2nd parameter wins outright)
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. CHARACTER TABLES
--------------------------------------------------------------------------
local DIGRAPHS = {
["xw"] = "xʷ",
["rr"] = "r",
["ll"] = "ɫ",
}
local SINGLES = {
["a"] = "ɑː", ["e"] = "æ", ["é"] = "ɛ", ["ê"] = "eː",
["i"] = "ɘ", ["î"] = "iː", ["o"] = "oː", ["u"] = "ʊ", ["û"] = "uː",
["b"] = "b", ["c"] = "d͡ʒ", ["ç"] = "t͡ʃ", ["d"] = "d", ["f"] = "f",
["g"] = "ɡ", ["h"] = "h", ["j"] = "ʒ", ["k"] = "k", ["l"] = "l",
["m"] = "m", ["n"] = "n", ["p"] = "p", ["q"] = "q", ["r"] = "ɾ",
["s"] = "s", ["ş"] = "ʃ", ["t"] = "t", ["v"] = "v", ["w"] = "w",
["x"] = "x", ["y"] = "j", ["z"] = "z",
["ẍ"] = "ɣ", ["ḧ"] = "ħ", ["ʿ"] = "ʕ", ["'"] = "ʕ",
["ł"] = "ɫ", ["ň"] = "ŋ", ["ř"] = "r", ["ü"] = "yː",
["ṣ"] = "sˤ", ["ṭ"] = "tˤ", ["ẓ"] = "zˤ",
}
local UPPER_TO_LOWER = {
["É"] = "é", ["Ê"] = "ê", ["Î"] = "î", ["Û"] = "û", ["Ş"] = "ş",
["Ç"] = "ç", ["Ł"] = "ł", ["Ň"] = "ň", ["Ř"] = "ř", ["Ü"] = "ü",
["Ṣ"] = "ṣ", ["Ṭ"] = "ṭ", ["Ẓ"] = "ẓ", ["Ẍ"] = "ẍ", ["Ḧ"] = "ḧ",
}
local IS_VOWEL_LETTER = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
local IS_VOWEL_OUTPUT = {
["ɑː"] = true, ["æ"] = true, ["ɛ"] = true, ["eː"] = true, ["ɘ"] = true,
["iː"] = true, ["oː"] = true, ["ʊ"] = true, ["uː"] = true, ["yː"] = true,
["ɔ"] = true,
}
local STRESS_MARK = "ˈ"
local QUOTE = '"'
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lowerHac(text)
text = u.lower(text)
local out = {}
for ch in u.gmatch(text, ".") do
out[#out + 1] = UPPER_TO_LOWER[ch] or ch
end
return table.concat(out)
end
local function splitChars(text)
local chars = {}
for ch in u.gmatch(text, ".") do
chars[#chars + 1] = ch
end
return chars
end
-- Detects a word-final -(e)we suffix realized as a single [ɔ] (rule e):
-- • "...Cewe" (e preceded by a consonant) -> "ewe" (3 letters)
-- • "...{i/î/u/û}we" (we preceded by i/î/u/û) -> "we" (2 letters)
local function findWeSuffix(chars)
local n = #chars
if n >= 2 and chars[n - 1] == "w" and chars[n] == "e" then
if n >= 3 and chars[n - 2] == "e" then
local prev = chars[n - 3]
if prev == nil or not IS_VOWEL_LETTER[prev] then
return { start = n - 2, len = 3 }
end
end
local prev = chars[n - 2]
if prev == "i" or prev == "î" or prev == "u" or prev == "û" then
return { start = n - 1, len = 2 }
end
end
return nil
end
-- Maps one input letter to IPA, applying context-sensitive rules:
-- (a) d -> ð after a vowel, or between r and a following vowel
-- (c) n -> ŋ before g/k
-- (d) o -> ʊ (unstressed, before another vowel)
local function mapSingle(chars, i)
local c = chars[i]
if c == "n" then
local nxt = chars[i + 1]
if nxt == "g" or nxt == "k" then
return "ŋ"
end
return "n"
end
if c == "d" then
local prev = chars[i - 1]
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[prev] then
return "ð"
elseif prev == "r" and IS_VOWEL_LETTER[nxt] then
return "ð"
end
return "d"
end
if c == "o" then
local nxt = chars[i + 1]
if IS_VOWEL_LETTER[nxt] then
return "ʊ"
end
return SINGLES["o"]
end
return SINGLES[c] or c
end
--------------------------------------------------------------------------
-- 3. TOKENIZER
--------------------------------------------------------------------------
local function tokenize(word)
local chars = splitChars(word)
local n = #chars
local weSuffix = findWeSuffix(chars)
local tokens = {}
local stressBefore = nil
local i = 1
while i <= n do
local c1, c2, c3 = chars[i], chars[i + 1], chars[i + 2]
if weSuffix and i == weSuffix.start then
tokens[#tokens + 1] = "ɔ"
i = i + weSuffix.len
elseif c2 == QUOTE and (
(c1 == "r" and c3 == "r") or
(c1 == "l" and c3 == "l") or
(c1 == "x" and c3 == "w")
) then
tokens[#tokens + 1] = mapSingle(chars, i)
tokens[#tokens + 1] = mapSingle(chars, i + 2)
i = i + 3
elseif c1 == "r" and c2 == "r" then
tokens[#tokens + 1] = DIGRAPHS["rr"]; i = i + 2
elseif c1 == "l" and c2 == "l" then
tokens[#tokens + 1] = DIGRAPHS["ll"]; i = i + 2
elseif c1 == "x" and c2 == "w" then
tokens[#tokens + 1] = DIGRAPHS["xw"]; i = i + 2
elseif c1 == QUOTE then
stressBefore = #tokens + 1
i = i + 1
else
tokens[#tokens + 1] = mapSingle(chars, i)
i = i + 1
end
end
return tokens, stressBefore
end
-- Automatic stress: last syllable.
local function placeAutoStress(tokens)
local lastVowel = nil
for idx = #tokens, 1, -1 do
if IS_VOWEL_OUTPUT[tokens[idx]] then
lastVowel = idx
break
end
end
if not lastVowel then
return tokens
end
local onset = lastVowel
local k = lastVowel - 1
while k >= 1 and not IS_VOWEL_OUTPUT[tokens[k]] do
onset = k
k = k - 1
end
table.insert(tokens, onset, STRESS_MARK)
return tokens
end
--------------------------------------------------------------------------
-- 4. WORD / PHRASE CONVERSION
--------------------------------------------------------------------------
function p._convertWord(word)
if word == "" then return "" end
local tokens, stressBefore = tokenize(word)
if stressBefore then
table.insert(tokens, stressBefore, STRESS_MARK)
else
tokens = placeAutoStress(tokens)
end
return table.concat(tokens)
end
function p._convert(text)
text = lowerHac(mw.text.trim(text))
local words = {}
for w in u.gmatch(text, "%S+") do
words[#words + 1] = p._convertWord(w)
end
return table.concat(words, " ")
end
--------------------------------------------------------------------------
-- 5. OUTPUT FORMATTING
--------------------------------------------------------------------------
local function formatOutput(ipa)
return string.format(
'<span class="IPA" title="Representation in the International Phonetic Alphabet (IPA)">[%s]</span>',
ipa
)
end
--------------------------------------------------------------------------
-- 6. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = v end
end
for k, v in pairs(frame.args) do args[k] = v end
return args
end
function p.IPA(frame)
local args = getArgs(frame)
local input = args[1]
local manual = args[2]
if manual and mw.text.trim(manual) ~= "" then
return formatOutput(mw.text.trim(manual))
end
if not input or mw.text.trim(input) == "" then
return ""
end
local ok, ipa = pcall(p._convert, input)
if not ok then
return formatOutput(input) .. "[[Category:Pages with hac-IPA errors]]"
end
return formatOutput(ipa)
end
return p
tb3u3a6poc3e4leii84s69w9uy2j5d8
Şablon:hac-IPA
10
1357754
6241823
2026-07-12T15:50:24Z
Kurdanparez
14556
Rûpel bi "<includeonly>{{#invoke:hac-IPA|IPA|{{{1|}}}|{{{2|}}}}}</includeonly><noinclude>{{hac-IPA|kerdewe}}</noinclude>" hat çêkirin
6241823
wikitext
text/x-wiki
<includeonly>{{#invoke:hac-IPA|IPA|{{{1|}}}|{{{2|}}}}}</includeonly><noinclude>{{hac-IPA|kerdewe}}</noinclude>
0jt95evp00rl7zk3tvlw4lb01jq1zz5
6241825
6241823
2026-07-12T16:02:03Z
Kurdanparez
14556
6241825
wikitext
text/x-wiki
<includeonly>{{#invoke:hac-IPA|IPA|{{{1|}}}|{{{2|}}}}}</includeonly><noinclude>{{belgekirin}}{{hac-IPA|kerdewe}}</noinclude>
2hzpyyovbrp07nar6hrsr22kacqu1tc
6241832
6241825
2026-07-12T16:52:06Z
Kurdanparez
14556
6241832
wikitext
text/x-wiki
<includeonly>[[IPA]]<sup>([[Wîkîferheng:IPA kurdî|kilîd]])</sup>: {{#invoke:hac-IPA|IPA|{{{1|}}}|{{{2|}}}}}</includeonly><noinclude>{{belgekirin}}{{hac-IPA|kerdewe}}</noinclude>
dqc1lmt1k9a9zdszs6h5z1ya85dy8lo
Şablon:hac-IPA/belge
10
1357755
6241826
2026-07-12T16:07:50Z
Kurdanparez
14556
Rûpel bi "{{belgekirin/binrûpel}} == Bikaranîn == Hewramî (goranî) bi tîpên kurdî yên şikilê erebî dinivîse, wek zaravayên soranî û başûrî. Ji ber vê, siftê bi tîpên latinî re çerx bike, ji wê şûnve di şablonê de binivîse. Eger tu dixwazî bi şikilekê din binivîsî, te bixwe jî IPA binivîsî. === Mînak === <syntaxhighlight>{{hac-IPA|kerdey}}</syntaxhighlight> {{hac-IPA|kerdey}} <syntaxhighlight>{{hac-IPA|ro}}</syntaxhighlight> {{hac-IPA|..." hat çêkirin
6241826
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
== Bikaranîn ==
Hewramî (goranî) bi tîpên kurdî yên şikilê erebî dinivîse, wek zaravayên soranî û başûrî. Ji ber vê, siftê bi tîpên latinî re çerx bike, ji wê şûnve di şablonê de binivîse. Eger tu dixwazî bi şikilekê din binivîsî, te bixwe jî IPA binivîsî.
=== Mînak ===
<syntaxhighlight>{{hac-IPA|kerdey}}</syntaxhighlight>
{{hac-IPA|kerdey}}
<syntaxhighlight>{{hac-IPA|ro}}</syntaxhighlight>
{{hac-IPA|ro}}
<syntaxhighlight>{{hac-IPA|rro}}</syntaxhighlight>
{{hac-IPA|rro}}
<syntaxhighlight>{{hac-IPA||bæθtʈ}}</syntaxhighlight>
{{hac-IPA||bæθtʈ}}
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
q15p5h1gpjppjku1uw8ke11ggxrs04s
6241827
6241826
2026-07-12T16:15:49Z
Kurdanparez
14556
6241827
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
== Bikaranîn ==
Hewramî (goranî) bi tîpên kurdî yên şikilê erebî dinivîse, wek zaravayên soranî û başûrî. Ji ber vê, siftê bi tîpên latinî re çerx bike, ji wê şûnve di şablonê de binivîse. Eger tu dixwazî bi şikilekê din binivîsî, te bixwe jî IPA binivîsî.
=== Mînak ===
<syntaxhighlight>{{hac-IPA|kerdey}}</syntaxhighlight>
{{hac-IPA|kerdey}}
<syntaxhighlight>{{hac-IPA|ro}}</syntaxhighlight>
{{hac-IPA|ro}}
<syntaxhighlight>{{hac-IPA|rro}}</syntaxhighlight>
{{hac-IPA|rro}}
<syntaxhighlight>{{hac-IPA|xwe}}</syntaxhighlight>
{{hac-IPA|xwe}}
<syntaxhighlight>{{hac-IPA||bæθtʈ}}</syntaxhighlight>
{{hac-IPA||bæθtʈ}}
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
odu9ndludj724m6y9errjirsce0erfp
6241829
6241827
2026-07-12T16:16:48Z
Kurdanparez
14556
6241829
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
== Bikaranîn ==
Hewramî (goranî) bi tîpên kurdî yên şikilê erebî dinivîse, wek zaravayên soranî û başûrî. Ji ber vê, siftê bi tîpên latinî re çerx bike, ji wê şûnve di şablonê de binivîse. Eger tu dixwazî bi şikilekê din binivîsî, te bixwe jî IPA binivîsî.
=== Mînak ===
<syntaxhighlight>{{hac-IPA|kerdey}}</syntaxhighlight>
{{hac-IPA|kerdey}}
<syntaxhighlight>{{hac-IPA|ro}}</syntaxhighlight>
{{hac-IPA|ro}}
<syntaxhighlight>{{hac-IPA|rro}}</syntaxhighlight>
{{hac-IPA|rro}}
<syntaxhighlight>{{hac-IPA|xwe}}</syntaxhighlight>
{{hac-IPA|xwe}}
<syntaxhighlight>{{hac-IPA|x"we}}</syntaxhighlight>
{{hac-IPA|x"we}}
<syntaxhighlight>{{hac-IPA||bæθtʈ}}</syntaxhighlight>
{{hac-IPA||bæθtʈ}}
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
btc43p9m1zwm9xanwri8y559ejz6ojb
کەردەی
0
1357756
6241831
2026-07-12T16:50:13Z
Kurdanparez
14556
Hawrami
6241831
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|kerdey}}
* {{hac-kîte}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|kirin}}
====Jê====
* {{q|hac|ئەوەکەردەی}}
====Etîmolojî====
Hevreha {{hv|zza|kerdene}}, {{hv|ckb|کردن}}, {{hv|ku|kirin}}.
pv87000pxd0szf8in0jffzs8h56dd1o
6241833
6241831
2026-07-12T16:52:36Z
Kurdanparez
14556
6241833
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|kerdey}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|kirin}}
====Jê====
* {{q|hac|ئەوەکەردەی}}
====Etîmolojî====
Hevreha {{hv|zza|kerdene}}, {{hv|ckb|کردن}}, {{hv|ku|kirin}}.
afj8sque9xh6zovq8xuk8xyrybccz7z
6241881
6241833
2026-07-12T21:29:34Z
Kurdanparez
14556
6241881
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|kerdey}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|kirin}}
====Jê====
* {{q|hac|ئەوەکەردەی}}
====Tewandin====
{{hac-tewîn-lk|kerdey|reh=ker|modal=no}}
====Etîmolojî====
Hevreha {{hv|zza|kerdene}}, {{hv|ckb|کردن}}, {{hv|ku|kirin}}.
kjqiygy6aiyr47q4pov8x1dhc71sn5s
یاگێ
0
1357757
6241834
2026-07-12T17:01:33Z
Kurdanparez
14556
Hawrami
6241834
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|yagê}}
===Navdêr===
{{navdêr|hac|z=m}}
# {{g|ku|cih}}, {{g|ku|der}}
# {{g|ku|nivîn}}
====Etîmolojî====
Ji ''*ya'' ("cih") + ''-gê'', hevreha {{g|ku|-geh}}. Peyiv bi xwe hevreha {{hv|zza|ca|z=n}}, {{hv|ckb|cêga}}, {{hv|ku|cih|z=n}}.
08ysx902x962clu1po4kijbf6jp2klr
یەوە
0
1357758
6241835
2026-07-12T17:07:04Z
Kurdanparez
14556
Rûpel bi "=={{ziman|hac}}== ===Bilêvkirin=== * {{hac-IPA}} ===Navdêr=== {{navdêr|hac|z=m}} # {{g|ku|ceh}}. ====Etîmolojî==== Hevreha {{hv|zza|cew|z=n}}, {{hv|ckb|جۆ}}, {{hv|ku|ceh|z=n}}." hat çêkirin
6241835
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA}}
===Navdêr===
{{navdêr|hac|z=m}}
# {{g|ku|ceh}}.
====Etîmolojî====
Hevreha {{hv|zza|cew|z=n}}, {{hv|ckb|جۆ}}, {{hv|ku|ceh|z=n}}.
0nndfgioi8fdu9g9x33k9ia4d40s6nn
6241837
6241835
2026-07-12T17:16:07Z
Kurdanparez
14556
6241837
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA}}
===Navdêr===
{{navdêr|hac|z=m}}
# {{g|ku|ceh}}.
====Etîmolojî====
Hevreha {{hv|zza|cew|z=n}}, {{hv|ckb|جۆ}}, {{hv|ku|ceh|z=n}}.
[[Kategorî:Peyvên hewramî bi paşgira -e (mêker)]]
jt2mjnt3fi3w63cpdfji0r23wd8q5cv
6241839
6241837
2026-07-12T17:18:18Z
Kurdanparez
14556
6241839
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA}}
===Navdêr===
{{navdêr|hac|z=m}}
# {{g|ku|ceh}}.
====Etîmolojî====
Hevreha {{hv|zza|cew|z=n}}, {{hv|ckb|جۆ}}, {{hv|ku|ceh|z=n}}.
[[Kategorî:Peyvên hewramî bi paşgira ـە (mêker)]]
snl18mzv7kbvo9m460gk8pnlhiic6oj
ـە
0
1357759
6241836
2026-07-12T17:15:04Z
Kurdanparez
14556
hawrami
6241836
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA}}
===Paşgir===
{{paşgir|hac}}
# Paşgirekê mêker, eger paşgir di peyivê de sivik (unstressed) e.
# Paşgirekê nêrker, eger paşgir di peyivê de giran (stressed) e.
====Bide ber====
* {{q|hac|ـی}}
====Etîmolojî====
Hevreha {{hv|zza|-e}}.
===Çavkanî===
* D. N. MacKenzie (1966), The Dialect of Awroman: "With nouns having no natural gender the distinction of grammatical gender is mainly dependent on the form of the word. Thus nouns which in their simple form end in a consonant, or in the stressed vowels -a [-e], -i [-î], -o, -u, are masculine. Those ending in unstressed -a [-e] or -i [-î], or in stressed-e [-ê], are feminine. Most nouns ending in -ā [-a] are masculine, but a few are feminine"
q8k7etq2s25vme1u2z09hvg4avdshy1
6241838
6241836
2026-07-12T17:18:01Z
Kurdanparez
14556
6241838
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA}}
===Paşgir 1===
{{paşgir|hac}}
# Paşgirekê mêker, eger paşgir di peyivê de sivik (unstressed) e.
====Jê====
{{paşgirbibîne|hac|id=mêker}}
====Bide ber====
* {{q|hac|ـی}}
====Etîmolojî====
Hevreha {{hv|zza|-e}}.
===Paşgir 2===
{{paşgir|hac}}
# Paşgirekê nêrker, eger paşgir di peyivê de giran (stressed) e.
===Çavkanî===
* D. N. MacKenzie (1966), The Dialect of Awroman: "With nouns having no natural gender the distinction of grammatical gender is mainly dependent on the form of the word. Thus nouns which in their simple form end in a consonant, or in the stressed vowels -a [-e], -i [-î], -o, -u, are masculine. Those ending in unstressed -a [-e] or -i [-î], or in stressed-e [-ê], are feminine. Most nouns ending in -ā [-a] are masculine, but a few are feminine"
k9dl3q954fseswzo3bhio31uqetl8yg
veyve
0
1357760
6241843
2026-07-12T17:25:24Z
Kurdanparez
14556
Rûpel bi "=={{ziman|zza}}== ===Bilêvkirin=== * (''Navdêr 1'') {{zza-IPA|"veyve}} * (''Navdêr 2'') {{zza-IPA|vey"ve}} ===Navdêr 1=== {{navdêr|zza|z=m}} # {{g|ku|bûk}} ====Etîmolojî==== Hevreha {{hv|hac|وەیوە|z=m}}, {{hv|ku|bûk}}. ===Navdêr 2=== {{navdêr|zza|z=n}} # {{g|ku|dawet}}, {{g|ku|zewac}} [[Kategorî:Peyvên zazakî bi paşgira -e (mêker)]] [[Kategorî:Peyvên zazakî bi paşgira -e]]" hat çêkirin
6241843
wikitext
text/x-wiki
=={{ziman|zza}}==
===Bilêvkirin===
* (''Navdêr 1'') {{zza-IPA|"veyve}}
* (''Navdêr 2'') {{zza-IPA|vey"ve}}
===Navdêr 1===
{{navdêr|zza|z=m}}
# {{g|ku|bûk}}
====Etîmolojî====
Hevreha {{hv|hac|وەیوە|z=m}}, {{hv|ku|bûk}}.
===Navdêr 2===
{{navdêr|zza|z=n}}
# {{g|ku|dawet}}, {{g|ku|zewac}}
[[Kategorî:Peyvên zazakî bi paşgira -e (mêker)]] [[Kategorî:Peyvên zazakî bi paşgira -e]]
7a40ggjqad74b1u1xmr4b57fhf0souk
6241847
6241843
2026-07-12T17:35:03Z
Kurdanparez
14556
6241847
wikitext
text/x-wiki
=={{ziman|zza}}==
===Bilêvkirin===
* (''Navdêr 1'') {{zza-IPA|"veyve}}
* (''Navdêr 2'') {{zza-IPA|vey"ve}}
===Navdêr 1===
{{navdêr|zza|z=m}}
# {{g|ku|bûk}}
====Tewandin====
{{zza-tewîn-nav|z=m}}
====Etîmolojî====
Hevreha {{hv|hac|وەیوە|z=m}}, {{hv|ku|bûk}}.
===Navdêr 2===
{{navdêr|zza|z=n}}
# {{g|ku|dawet}}, {{g|ku|zewac}}
====Tewandin====
{{zza-tewîn-nav|z=n}}
[[Kategorî:Peyvên zazakî bi paşgira -e (mêker)]] [[Kategorî:Peyvên zazakî bi paşgira -e]]
9ggnzujr1fb2p4yr71wgiblealud52k
وەروە
0
1357761
6241844
2026-07-12T17:30:50Z
Kurdanparez
14556
hawrami
6241844
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|"werwe}}
====Navdêr====
{{navdêr|hac|z=m}}
# {{g|ku|berf}}
====Etîmolojî====
Hevreha {{hv|zza|vewre}}, {{hv|ku|berf}} yan jî ''{{g|ku|befr}}''.
[[Kategorî:Peyvên hewramî bi paşgira ـە (mêker)]]
osrzbthprgxa714e99s9u9haa6qbrwp
6241849
6241844
2026-07-12T18:13:31Z
Wikihez
7344
/* {{ziman|hac}} */
6241849
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|"werwe}}
====Navdêr====
{{navdêr|hac|z=m}}
# {{g|ku|berf}}
====Etîmolojî====
{{qf|hac|ـە<id:mêker>|nivîsna=1}}Hevreha {{hv|zza|vewre}}, {{hv|ku|berf}} yan jî {{q|ku|befr}}.
mg4s2l2w6bqzkssvyzpk8xr780dxf6y
6241850
6241849
2026-07-12T18:17:47Z
Wikihez
7344
([[m:Special:MyLanguage/User:Jon Harald Søby/diffedit|diffedit]])
6241850
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|"werwe}}
====Navdêr====
{{navdêr|hac|z=m}}
# {{g|ku|berf}}
====Etîmolojî====
Hevreha {{hv|zza|vewre}}, {{hv|ku|berf}} yan jî {{q|ku|befr}}.
[[Kategorî:Peyvên hewramî bi paşgira ـە (mêker)]]
a64jlgfixe5hafrqv0ksjw1kjpfovb0
destnivîsar
0
1357762
6241861
2026-07-12T20:15:13Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]]) +ku:navdêr:Kitêb an belgeyeke din a ku bi xetên destî hatiye nivîsin.
6241861
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|destnivîsar|mê}}
{{navdêr|ku|c=m}}
# {{e|ku|kitêb}} [[kitêb|Kitêb]] an [[belgeyeke]] [[din]] a ku [[bi]] [[xetên]] [[destî]] [[hatiye]] [[nivîsin]].
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê1 pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke xweşbext, di nav '''destnivîsareke''' şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike.|nivîskar=Ergin Öpengin|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|kovar=The Journal of Mesopotamian Studies|cild=3|hejmar=1|sal=2018|rûpel=45|url=https://dergipark.org.tr/tr/download/article-file/450470}}
==== Etîmolojî ====
Ji {{qertaf|ku|dest|nivîsar}}.
==== Binêre herwiha ====
* {{g|ku|destxet}}
==== Werger ====
{{werger-ser|kitêb an belgeyeke din a ku bi xetên destî hatiye nivîsin|1}}
* {{Z|en}}: {{W|en|manuscript}}
* {{Z|tr}}: {{W|tr|el yazması}}
{{werger-bin}}
4sm04bqd4stx27e8273t1cwrcademjz
6241863
6241861
2026-07-12T20:27:49Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241863
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|destnivîsar|mê}}
{{navdêr|ku|c=m}}
# {{e|ku|kitêb}} [[kitêb|Kitêb]] an [[belgeyeke]] [[din]] a ku [[bi]] [[xetên]] [[destî]] [[hatiye]] [[nivîsin]].
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke xweşbext, di nav '''destnivîsareke''' şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike.|nivîskar=Ergin Öpengin|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|kovar=The Journal of Mesopotamian Studies|cild=3|hejmar=1|sal=2018|rûpel=45|url=https://dergipark.org.tr/tr/download/article-file/450470}}
==== Etîmolojî ====
Ji {{qertaf|ku|dest|nivîsar}}.
==== Binêre herwiha ====
* {{g|ku|destxet}}
==== Werger ====
{{werger-ser|kitêb an belgeyeke din a ku bi xetên destî hatiye nivîsin|1}}
* {{Z|en}}: {{W|en|manuscript}}
* {{Z|tr}}: {{W|tr|el yazması}}
{{werger-bin}}
qfwqgu6icbfwbrures84ogepkg4e1t6
6241869
6241863
2026-07-12T20:56:28Z
Wikihez
7344
/* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re
6241869
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|destnivîsar|mê}}
{{navdêr|ku|c=m}}
# {{K|ku|kitêb}} [[kitêb|Kitêb]] an [[belgeyeke]] [[din]] a ku [[bi]] [[xetên]] [[destî]] [[hatiye]] [[nivîsin]].
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke xweşbext, di nav '''destnivîsareke''' şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike.|nivîskar=Ergin Öpengin|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|kovar=The Journal of Mesopotamian Studies|cild=3|hejmar=1|sal=2018|rûpel=45|url=https://dergipark.org.tr/tr/download/article-file/450470}}
==== Etîmolojî ====
Ji {{qertaf|ku|dest|nivîsar}}.
==== Binêre herwiha ====
* {{g|ku|destxet}}
==== Werger ====
{{werger-ser|kitêb an belgeyeke din a ku bi xetên destî hatiye nivîsin|1}}
* {{Z|en}}: {{W|en|manuscript}}
* {{Z|tr}}: {{W|tr|el yazması}}
{{werger-bin}}
5pub5gvsguvzzc282c2w1j60w6dfuqe
6241939
6241869
2026-07-12T23:48:25Z
Balyozbot
7867
Sererastkirin/rêzkirina şablonên {{[[Şablon:W-|W-]]}}, {{[[Şablon:W+|W+]]}} ([[User:Balyozxane/updateW.py|updateW]])
6241939
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|destnivîsar|mê}}
{{navdêr|ku|c=m}}
# {{K|ku|kitêb}} [[kitêb|Kitêb]] an [[belgeyeke]] [[din]] a ku [[bi]] [[xetên]] [[destî]] [[hatiye]] [[nivîsin]].
#* {{jêder-kovar|ku|jêgirtin=M. Clement Huartê pisporê ziman û kulturên rojhilata nêzîk, ber bi dawiya sedsala 19an, bi tesadufeke xweşbext, di nav '''destnivîsareke''' şi’ra farsî ya arşîva xwe de, bi ser rûpelekê ve dibe, ku tê de mustensixê destnivîsarê, bi usûla salnameyan an kronîkan, ji dawiya sedsala 17an heta ber bi dawiya sedsala 18an, bi rengekî kronolojîk, hejmareke qewimînên tarîxî yên li herêma Badînan û li derdorên wê, anku bi giştî yên bakurê Mezopotamyayê, rêz dike.|nivîskar=Ergin Öpengin|sernav=Kronikek ji Sedsala 18an li ser Tarîxa Badînan û Mezopotamyaya Bakurî|kovar=The Journal of Mesopotamian Studies|cild=3|hejmar=1|sal=2018|rûpel=45|url=https://dergipark.org.tr/tr/download/article-file/450470}}
==== Etîmolojî ====
Ji {{qertaf|ku|dest|nivîsar}}.
==== Binêre herwiha ====
* {{g|ku|destxet}}
==== Werger ====
{{werger-ser|kitêb an belgeyeke din a ku bi xetên destî hatiye nivîsin|1}}
* {{Z|en}}: {{W+|en|manuscript}}
* {{Z|tr}}: {{W+|tr|el yazması}}
{{werger-bin}}
6m000tro1jq5u9mns5zfshshmzwfnw5
golden ages
0
1357763
6241865
2026-07-12T20:45:56Z
Wikihez
7344
Çêkirina formên [[golden age]] ([[WF:BILEZ|Bi lez]])
6241865
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Formeke navdêrê ===
{{navdêr|en|form=erê}}
# {{pirjimar|en|golden age}}
kt9ijzutn2a8uus17mbi2wdkmf1zg4y
Modul:hac-tewîn-lk
828
1357764
6241868
2026-07-12T20:56:02Z
Kurdanparez
14556
Rûpel bi "-- Module:hac-tewîn -- Generates a horizontal Present / Imperative / Imperfect conjugation table -- for Hawrami, from a present stem, for {{hac-tewîn-lk}}. -- Self-contained: does not require or share code with Module:hac-IPA. local p = {} local u = mw.ustring -------------------------------------------------------------------------- -- 1. DATA -------------------------------------------------------------------------- local VOWELS = { ["a"] = true, ["e"] =..." hat çêkirin
6241868
Scribunto
text/plain
-- Module:hac-tewîn
-- Generates a horizontal Present / Imperative / Imperfect conjugation table
-- for Hawrami, from a present stem, for {{hac-tewîn-lk}}.
-- Self-contained: does not require or share code with Module:hac-IPA.
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. DATA
--------------------------------------------------------------------------
local VOWELS = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
-- Vowels that trigger the -ewe -> ó reduction.
local IU_VOWELS = { ["î"] = true, ["û"] = true }
local PERSONS = { "1sg", "2sg", "3sg", "1pl", "2pl", "3pl" }
-- {consonant-final form, vowel-final form}. Same value twice = no alternation.
local PRESENT_ENDINGS = {
["1sg"] = { "û", "w" },
["2sg"] = { "î", "y" },
["3sg"] = { "o", "o" },
["1pl"] = { "mê", "ymê" },
["2pl"] = { "dê", "ydê" },
["3pl"] = { "a", "a" },
}
-- Only 2sg / 2pl exist. 2pl is an ASSUMPTION (see note above the code).
local IMPERATIVE_ENDINGS = {
["2sg"] = { "a", "" },
["2pl"] = { "dê", "ydê" },
}
-- Built on the present stem; single form each, no consonant/vowel split.
local IMPERFECT_ENDINGS = {
["1sg"] = "ênê", ["2sg"] = "ênî", ["3sg"] = "ê",
["1pl"] = "ênmê", ["2pl"] = "êndê", ["3pl"] = "ênê",
}
local PRONOUNS = {
["1sg"] = "êmin",
["2sg"] = "to",
["3sg"] = '<span title="dûr">êḏ</span>/<span title="nêzik">aḏ</span> <small>(n.)</small><br/>'
.. '<span title="dûr">êḏe</span>/<span title="nêzik">aḏe</span> <small>(m.)</small>',
["1pl"] = "êma",
["2pl"] = "şime",
["3pl"] = '<span title="dûr">êḏê</span>/<span title="nêzik">aḏê</span>',
}
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lastChar(s)
return u.sub(s, -1)
end
local function firstChar(s)
return u.sub(s, 1, 1)
end
local function isVowel(ch)
return VOWELS[ch] == true
end
-- Picks the consonant/vowel-final allomorph and attaches it to the stem.
local function attachEnding(stem, endingPair)
local vowelFinal = isVowel(lastChar(stem))
local ending = vowelFinal and endingPair[2] or endingPair[1]
return stem .. ending
end
-- Present-tense modal prefix m(i)-.
-- consonant-initial -> mi-
-- vowel-initial (not e) -> m-
-- e-initial -> mi- REPLACES the e entirely
local function applyModalPresent(form)
local fc = firstChar(form)
if fc == "e" then
return "mi" .. u.sub(form, u.len(fc) + 1)
elseif isVowel(fc) then
return "m" .. form
else
return "mi" .. form
end
end
-- Imperative modal prefix b(i)-. No e-drop exception here.
local function applyModalImperative(form)
local fc = firstChar(form)
if isVowel(fc) then
return "b" .. form
else
return "bi" .. form
end
end
-- Suffixes a preverb (ene / ere / ewe) onto a finite form.
local function attachPreverb(form, preverb)
if not preverb or preverb == "" then
return form
end
if preverb == "ewe" then
local lc = lastChar(form)
if not isVowel(lc) then
return form .. "ó" -- after any consonant
elseif IU_VOWELS[lc] then
return form .. "ó" -- after î / û
else
return form .. "we" -- after any other vowel
end
else
return form .. preverb -- ene / ere: unreduced (assumption)
end
end
--------------------------------------------------------------------------
-- 3. BUILDERS
--------------------------------------------------------------------------
local function buildPresent(stem, preverb, useModal, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if overrides["prs_" .. person] then
out[person] = overrides["prs_" .. person]
else
local base = attachEnding(stem, PRESENT_ENDINGS[person])
local plain = attachPreverb(base, preverb)
if useModal then
local modal = attachPreverb(applyModalPresent(base), preverb)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
end
return out
end
local function buildImperative(stem, preverb, useModal, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if person == "2sg" or person == "2pl" then
if overrides["imv_" .. person] then
out[person] = overrides["imv_" .. person]
else
local base = attachEnding(stem, IMPERATIVE_ENDINGS[person])
local plain = attachPreverb(base, preverb)
if useModal then
local modal = attachPreverb(applyModalImperative(base), preverb)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
else
out[person] = "–"
end
end
return out
end
local function buildImperfect(stem, preverb, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if overrides["ipf_" .. person] then
out[person] = overrides["ipf_" .. person]
else
local base = stem .. IMPERFECT_ENDINGS[person]
out[person] = attachPreverb(base, preverb)
end
end
return out
end
--------------------------------------------------------------------------
-- 4. OUTPUT
--------------------------------------------------------------------------
local function renderTable(infinitive, present, imperative, imperfect)
local rows = {}
table.insert(rows, '<div class="NavFrame" style="font-size:100%; background-color:#f8f9fa; width:fit-content; margin:0.5em 0;">')
table.insert(rows, '<div class="NavHead" style="background-color:#f8f9fa;">Tewandina \'\'' .. infinitive .. '\'\'</div>')
table.insert(rows, '<div class="NavContent" style="border-top-color:transparent; padding:3px;">')
table.insert(rows, '{| class="wikitable" style="width:100%; margin:0; background-color:#ffffff; text-align:center;"')
table.insert(rows, '|-')
table.insert(rows, '! style="background-color:#f2f2f2;" | ')
for _, person in ipairs(PERSONS) do
table.insert(rows, '! style="background-color:#f2f2f2;" | ' .. PRONOUNS[person])
end
table.insert(rows, '|-')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema niha')
for _, person in ipairs(PERSONS) do
table.insert(rows, '| ' .. present[person])
end
table.insert(rows, '|-')
table.insert(rows, '! style="background-color:#f2f2f2;" | Fermanî')
for _, person in ipairs(PERSONS) do
table.insert(rows, '| ' .. imperative[person])
end
table.insert(rows, '|-')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema borî ya nediyar')
for _, person in ipairs(PERSONS) do
table.insert(rows, '| ' .. imperfect[person])
end
table.insert(rows, '|}')
table.insert(rows, '</div></div>')
return table.concat(rows, "\n")
end
--------------------------------------------------------------------------
-- 5. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = mw.text.trim(v) end
end
for k, v in pairs(frame.args) do args[k] = mw.text.trim(v) end
return args
end
-- Auto-detects a leading ene-/ere-/ewe- preverb from the infinitive,
-- unless overridden by the |preverb= parameter.
local function detectPreverb(infinitive, explicitPreverb)
if explicitPreverb == "none" then
return ""
end
if explicitPreverb and explicitPreverb ~= "" then
return explicitPreverb
end
for _, pv in ipairs({ "ene", "ere", "ewe" }) do
if u.sub(infinitive, 1, u.len(pv)) == pv then
return pv
end
end
return ""
end
function p.show(frame)
local args = getArgs(frame)
local infinitive = args[1] or ""
local stem = args.reh
if not stem or stem == "" then
return '<strong class="error">hac-tewîn-lk: parametreya "reh" (rehê dema niha) kêm e.</strong>'
end
local preverb = detectPreverb(infinitive, args.preverb)
local useModal = not (args.modal == "no" or args.modal == "off" or args.modal == "0")
local present = buildPresent(stem, preverb, useModal, args)
local imperative = buildImperative(stem, preverb, useModal, args)
local imperfect = buildImperfect(stem, preverb, args)
return renderTable(infinitive, present, imperative, imperfect)
end
return p
gfazk2w9bvlpdxa86mgybh84zs2yfz4
6241870
6241868
2026-07-12T21:05:49Z
Kurdanparez
14556
6241870
Scribunto
text/plain
-- Module:hac-tewîn
-- Generates a Present / Imperative / Imperfect conjugation table for Hawrami,
-- from a present stem, for {{hac-tewîn-lk}}. Self-contained.
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. DATA
--------------------------------------------------------------------------
local VOWELS = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
local IU_VOWELS = { ["î"] = true, ["û"] = true }
local PERSONS = { "1sg", "2sg", "3sg", "1pl", "2pl", "3pl" }
local PRESENT_ENDINGS = {
["1sg"] = { "û", "w" },
["2sg"] = { "î", "y" },
["3sg"] = { "o", "o" },
["1pl"] = { "mê", "ymê" },
["2pl"] = { "dê", "ydê" },
["3pl"] = { "a", "a" },
}
-- Only 2sg / 2pl exist; 2pl confirmed to reuse the present 2pl shape.
local IMPERATIVE_ENDINGS = {
["2sg"] = { "a", "" },
["2pl"] = { "dê", "ydê" },
}
local IMPERFECT_ENDINGS = {
["1sg"] = "ênê", ["2sg"] = "ênî", ["3sg"] = "ê",
["1pl"] = "ênmê", ["2pl"] = "êndê", ["3pl"] = "ênê",
}
local PRONOUNS = {
["1sg"] = "êmin",
["2sg"] = "to",
["3sg"] = '<span title="dûr">êḏ</span>/<span title="nêzik">aḏ</span> <small>(n.)</small><br/>'
.. '<span title="dûr">êḏe</span>/<span title="nêzik">aḏe</span> <small>(m.)</small>',
["1pl"] = "êma",
["2pl"] = "şime",
["3pl"] = '<span title="dûr">êḏê</span>/<span title="nêzik">aḏê</span>',
}
local GROUP_LABEL = { ["1sg"] = "Yekjimar", ["1pl"] = "Pirrjimar" }
local GROUP_ROWSPAN = 3
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lastChar(s) return u.sub(s, -1) end
local function firstChar(s) return u.sub(s, 1, 1) end
local function isVowel(ch) return VOWELS[ch] == true end
local function attachEnding(stem, endingPair)
local vowelFinal = isVowel(lastChar(stem))
local ending = vowelFinal and endingPair[2] or endingPair[1]
return stem .. ending
end
-- Present-tense modal prefix m(i)-.
-- consonant-initial -> mi-
-- vowel-initial (not e) -> m-
-- e-initial -> mi- REPLACES the e entirely
local function applyModalPresent(form)
local fc = firstChar(form)
if fc == "e" then
return "mi" .. u.sub(form, 2)
elseif isVowel(fc) then
return "m" .. form
else
return "mi" .. form
end
end
-- Imperative modal prefix b(i)-. No e-drop exception.
local function applyModalImperative(form)
local fc = firstChar(form)
if isVowel(fc) then
return "b" .. form
else
return "bi" .. form
end
end
-- Attaches a preverb (pre) to a finite form, with optional full-replacement
-- form (pre_p) used when the form is consonant-final or ends in î/û.
-- Otherwise: postvocalic -> drop pre's initial "e"; postconsonantal -> keep it.
local function attachPreverb(form, pre, prePart)
if not pre or pre == "" then
return form
end
local lc = lastChar(form)
local consonantFinal = not isVowel(lc)
local iuFinal = IU_VOWELS[lc] == true
if prePart and prePart ~= "" and (consonantFinal or iuFinal) then
return form .. prePart
end
if isVowel(lc) and firstChar(pre) == "e" then
return form .. u.sub(pre, 2)
else
return form .. pre
end
end
--------------------------------------------------------------------------
-- 3. BUILDERS
--------------------------------------------------------------------------
local function getOverride(overrides, key)
local v = overrides[key]
if v and v ~= "" then return v end
return nil
end
local function buildPresent(stem, pre, prePart, useModal, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "prs_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, PRESENT_ENDINGS[person])
local plain = attachPreverb(base, pre, prePart)
if useModal then
local modal = attachPreverb(applyModalPresent(base), pre, prePart)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
end
return out
end
local function buildImperative(stem, pre, prePart, useModal, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if person == "2sg" or person == "2pl" then
local ov = getOverride(overrides, "imv_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, IMPERATIVE_ENDINGS[person])
local plain = attachPreverb(base, pre, prePart)
if useModal then
local modal = attachPreverb(applyModalImperative(base), pre, prePart)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
else
out[person] = "–"
end
end
return out
end
local function buildImperfect(stem, pre, prePart, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "ipf_" .. person)
if ov then
out[person] = ov
else
local base = stem .. IMPERFECT_ENDINGS[person]
out[person] = attachPreverb(base, pre, prePart)
end
end
return out
end
--------------------------------------------------------------------------
-- 4. OUTPUT — tenses horizontal, persons vertical
--------------------------------------------------------------------------
local function renderTable(infinitive, present, imperative, imperfect)
local rows = {}
table.insert(rows, '<div class="NavFrame" style="font-size:100%; background-color:#f8f9fa; width:fit-content; margin:0.5em 0;">')
table.insert(rows, '<div class="NavHead" style="background-color:#f8f9fa;">Tewandina \'\'' .. infinitive .. '\'\'</div>')
table.insert(rows, '<div class="NavContent" style="border-top-color:transparent; padding:3px;">')
table.insert(rows, '{| class="wikitable" style="width:100%; margin:0; background-color:#ffffff; text-align:center;"')
table.insert(rows, '|-')
table.insert(rows, '! colspan="2" style="background-color:#f2f2f2;" | ')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema niha')
table.insert(rows, '! style="background-color:#f2f2f2;" | Fermanî')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema borî ya nediyar')
for _, person in ipairs(PERSONS) do
table.insert(rows, '|-')
if GROUP_LABEL[person] then
table.insert(rows, '! rowspan="' .. GROUP_ROWSPAN .. '" style="background-color:#f2f2f2;" | ' .. GROUP_LABEL[person])
end
table.insert(rows, '! style="background-color:#f2f2f2;" | ' .. PRONOUNS[person])
table.insert(rows, '| ' .. present[person])
table.insert(rows, '| ' .. imperative[person])
table.insert(rows, '| ' .. imperfect[person])
end
table.insert(rows, '|}')
table.insert(rows, '</div></div>')
return table.concat(rows, "\n")
end
--------------------------------------------------------------------------
-- 5. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = mw.text.trim(v) end
end
for k, v in pairs(frame.args) do args[k] = mw.text.trim(v) end
return args
end
function p.show(frame)
local args = getArgs(frame)
local infinitive = args[1] or ""
local stem = args.reh
if not stem or stem == "" then
return '<strong class="error">hac-tewîn-lk: parametreya "reh" (rehê dema niha) kêm e.</strong>'
end
local pre = args.pre or ""
local prePart = args.pre_p or ""
local useModal = not (args.modal == "no" or args.modal == "off" or args.modal == "0")
local present = buildPresent(stem, pre, prePart, useModal, args)
local imperative = buildImperative(stem, pre, prePart, useModal, args)
local imperfect = buildImperfect(stem, pre, prePart, args)
return renderTable(infinitive, present, imperative, imperfect)
end
return p
7n7oe2vgciimd82uw3g54f4pnpxi18x
6241872
6241870
2026-07-12T21:21:34Z
Kurdanparez
14556
6241872
Scribunto
text/plain
-- Module:hac-tewîn
-- Generates a Present / Imperative / Imperfect conjugation table for Hawrami,
-- from a present stem, for {{hac-tewîn-lk}}. Self-contained.
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. DATA
--------------------------------------------------------------------------
local VOWELS = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
local IU_VOWELS = { ["î"] = true, ["û"] = true }
local PERSONS = { "1sg", "2sg", "3sg", "1pl", "2pl", "3pl" }
local PRESENT_ENDINGS = {
["1sg"] = { "û", "w" },
["2sg"] = { "î", "y" },
["3sg"] = { "o", "o" },
["1pl"] = { "mê", "ymê" },
["2pl"] = { "dê", "ydê" },
["3pl"] = { "a", "a" },
}
-- Only 2sg / 2pl exist; 2pl confirmed to reuse the present 2pl shape.
local IMPERATIVE_ENDINGS = {
["2sg"] = { "a", "" },
["2pl"] = { "dê", "ydê" },
}
local IMPERFECT_ENDINGS = {
["1sg"] = "ênê", ["2sg"] = "ênî", ["3sg"] = "ê",
["1pl"] = "ênmê", ["2pl"] = "êndê", ["3pl"] = "ênê",
}
-- add near the other constants
local function prependWord(form, word)
if word and word ~= "" then
return word .. " " .. form
end
return form
end
-- updated PRONOUNS with abbr + visible hover styling
local TOOLTIP_STYLE = 'style="cursor:help; border-bottom:1px dotted #555555;"'
local PRONOUNS = {
["1sg"] = "êmin",
["2sg"] = "to",
["3sg"] = '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏ</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏ</abbr> <small>(n.)</small><br/>'
.. '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏe</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏe</abbr> <small>(m.)</small>',
["1pl"] = "êma",
["2pl"] = "şime",
["3pl"] = '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏê</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏê</abbr>',
}
local GROUP_LABEL = { ["1sg"] = "Yekjimar", ["1pl"] = "Pirrjimar" }
local GROUP_ROWSPAN = 3
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lastChar(s) return u.sub(s, -1) end
local function firstChar(s) return u.sub(s, 1, 1) end
local function isVowel(ch) return VOWELS[ch] == true end
local function attachEnding(stem, endingPair)
local vowelFinal = isVowel(lastChar(stem))
local ending = vowelFinal and endingPair[2] or endingPair[1]
return stem .. ending
end
-- Present-tense modal prefix m(i)-.
-- consonant-initial -> mi-
-- vowel-initial (not e) -> m-
-- e-initial -> mi- REPLACES the e entirely
local function applyModalPresent(form)
local fc = firstChar(form)
if fc == "e" then
return "mi" .. u.sub(form, 2)
elseif isVowel(fc) then
return "m" .. form
else
return "mi" .. form
end
end
-- Imperative modal prefix b(i)-. No e-drop exception.
local function applyModalImperative(form)
local fc = firstChar(form)
if isVowel(fc) then
return "b" .. form
else
return "bi" .. form
end
end
-- Attaches a preverb (pre) to a finite form, with optional full-replacement
-- form (pre_p) used when the form is consonant-final or ends in î/û.
-- Otherwise: postvocalic -> drop pre's initial "e"; postconsonantal -> keep it.
local function attachPreverb(form, pre, prePart)
if not pre or pre == "" then
return form
end
local lc = lastChar(form)
local consonantFinal = not isVowel(lc)
local iuFinal = IU_VOWELS[lc] == true
if prePart and prePart ~= "" and (consonantFinal or iuFinal) then
return form .. prePart
end
if isVowel(lc) and firstChar(pre) == "e" then
return form .. u.sub(pre, 2)
else
return form .. pre
end
end
--------------------------------------------------------------------------
-- 3. BUILDERS
--------------------------------------------------------------------------
local function getOverride(overrides, key)
local v = overrides[key]
if v and v ~= "" then return v end
return nil
end
-- updated builders: added `word` parameter, applied via prependWord
local function buildPresent(stem, pre, prePart, useModal, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "prs_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, PRESENT_ENDINGS[person])
local plain = prependWord(attachPreverb(base, pre, prePart), word)
if useModal then
local modal = prependWord(attachPreverb(applyModalPresent(base), pre, prePart), word)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
end
return out
end
local function buildImperative(stem, pre, prePart, useModal, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if person == "2sg" or person == "2pl" then
local ov = getOverride(overrides, "imv_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, IMPERATIVE_ENDINGS[person])
local plain = prependWord(attachPreverb(base, pre, prePart), word)
if useModal then
local modal = prependWord(attachPreverb(applyModalImperative(base), pre, prePart), word)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
else
out[person] = "–"
end
end
return out
end
local function buildImperfect(stem, pre, prePart, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "ipf_" .. person)
if ov then
out[person] = ov
else
local base = stem .. IMPERFECT_ENDINGS[person]
out[person] = prependWord(attachPreverb(base, pre, prePart), word)
end
end
return out
end
--------------------------------------------------------------------------
-- 4. OUTPUT — tenses horizontal, persons vertical
--------------------------------------------------------------------------
local function renderTable(infinitive, stem, present, imperative, imperfect)
local rows = {}
table.insert(rows, '<div class="NavFrame" style="font-size:100%; background-color:#f8f9fa; width:fit-content; margin:0.5em 0;">')
table.insert(rows, '<div class="NavHead" style="background-color:#f8f9fa;">Tewandina \'\'' .. infinitive .. '\'\'</div>')
table.insert(rows, '<div style="background-color:#f8f9fa; font-size:90%; padding:2px 6px;">Rehê dema niha: \'\'\'' .. stem .. '\'\'\'</div>')
table.insert(rows, '<div class="NavContent" style="border-top-color:transparent; padding:3px;">')
table.insert(rows, '{| class="wikitable" style="width:100%; margin:0; background-color:#ffffff; text-align:center;"')
table.insert(rows, '|-')
table.insert(rows, '! colspan="2" style="background-color:#f2f2f2;" | ')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema niha')
table.insert(rows, '! style="background-color:#f2f2f2;" | Fermanî')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema borî ya nediyar')
for _, person in ipairs(PERSONS) do
table.insert(rows, '|-')
if GROUP_LABEL[person] then
table.insert(rows, '! rowspan="' .. GROUP_ROWSPAN .. '" style="background-color:#f2f2f2;" | ' .. GROUP_LABEL[person])
end
table.insert(rows, '! style="background-color:#f2f2f2;" | ' .. PRONOUNS[person])
table.insert(rows, '| ' .. present[person])
table.insert(rows, '| ' .. imperative[person])
table.insert(rows, '| ' .. imperfect[person])
end
table.insert(rows, '|}')
table.insert(rows, '</div></div>')
return table.concat(rows, "\n")
end
--------------------------------------------------------------------------
-- 5. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = mw.text.trim(v) end
end
for k, v in pairs(frame.args) do args[k] = mw.text.trim(v) end
return args
end
-- updated p.show
function p.show(frame)
local args = getArgs(frame)
local infinitive = args[1] or ""
local stem = args.reh
if not stem or stem == "" then
return '<strong class="error">hac-tewîn-lk: parametreya "reh" (rehê dema niha) kêm e.</strong>'
end
local pre = args.pre or ""
local prePart = args.pre_p or ""
local word = args["pêş"] or ""
local useModal = not (args.modal == "no" or args.modal == "off" or args.modal == "0")
local present = buildPresent(stem, pre, prePart, useModal, word, args)
local imperative = buildImperative(stem, pre, prePart, useModal, word, args)
local imperfect = buildImperfect(stem, pre, prePart, word, args)
return renderTable(infinitive, stem, present, imperative, imperfect)
end
return p
4syfmsssiruqh5e3uwem03f6urrdnuy
6241880
6241872
2026-07-12T21:26:49Z
Kurdanparez
14556
6241880
Scribunto
text/plain
-- Module:hac-tewîn
-- Generates a Present / Imperative / Imperfect conjugation table for Hawrami,
-- from a present stem, for {{hac-tewîn-lk}}. Self-contained.
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. DATA
--------------------------------------------------------------------------
local VOWELS = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
local IU_VOWELS = { ["î"] = true, ["û"] = true }
local PERSONS = { "1sg", "2sg", "3sg", "1pl", "2pl", "3pl" }
local PRESENT_ENDINGS = {
["1sg"] = { "û", "w" },
["2sg"] = { "î", "y" },
["3sg"] = { "o", "o" },
["1pl"] = { "mê", "ymê" },
["2pl"] = { "dê", "ydê" },
["3pl"] = { "a", "a" },
}
-- Only 2sg / 2pl exist; 2pl confirmed to reuse the present 2pl shape.
local IMPERATIVE_ENDINGS = {
["2sg"] = { "e", "" },
["2pl"] = { "dê", "ydê" },
}
local IMPERFECT_ENDINGS = {
["1sg"] = "ênê", ["2sg"] = "ênî", ["3sg"] = "ê",
["1pl"] = "ênmê", ["2pl"] = "êndê", ["3pl"] = "ênê",
}
-- add near the other constants
local function prependWord(form, word)
if word and word ~= "" then
return word .. " " .. form
end
return form
end
-- updated PRONOUNS with abbr + visible hover styling
local TOOLTIP_STYLE = 'style="cursor:help; border-bottom:1px dotted #555555;"'
local PRONOUNS = {
["1sg"] = "êmin",
["2sg"] = "to",
["3sg"] = '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏ</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏ</abbr> <small>(n.)</small><br/>'
.. '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏe</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏe</abbr> <small>(m.)</small>',
["1pl"] = "êma",
["2pl"] = "şime",
["3pl"] = '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏê</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏê</abbr>',
}
local GROUP_LABEL = { ["1sg"] = "Yekjimar", ["1pl"] = "Pirrjimar" }
local GROUP_ROWSPAN = 3
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lastChar(s) return u.sub(s, -1) end
local function firstChar(s) return u.sub(s, 1, 1) end
local function isVowel(ch) return VOWELS[ch] == true end
local function attachEnding(stem, endingPair)
local vowelFinal = isVowel(lastChar(stem))
local ending = vowelFinal and endingPair[2] or endingPair[1]
return stem .. ending
end
-- Present-tense modal prefix m(i)-.
-- consonant-initial -> mi-
-- vowel-initial (not e) -> m-
-- e-initial -> mi- REPLACES the e entirely
local function applyModalPresent(form)
local fc = firstChar(form)
if fc == "e" then
return "mi" .. u.sub(form, 2)
elseif isVowel(fc) then
return "m" .. form
else
return "mi" .. form
end
end
-- Imperative modal prefix b(i)-. No e-drop exception.
local function applyModalImperative(form)
local fc = firstChar(form)
if isVowel(fc) then
return "b" .. form
else
return "bi" .. form
end
end
-- Attaches a preverb (pre) to a finite form, with optional full-replacement
-- form (pre_p) used when the form is consonant-final or ends in î/û.
-- Otherwise: postvocalic -> drop pre's initial "e"; postconsonantal -> keep it.
local function attachPreverb(form, pre, prePart)
if not pre or pre == "" then
return form
end
local lc = lastChar(form)
local consonantFinal = not isVowel(lc)
local iuFinal = IU_VOWELS[lc] == true
if prePart and prePart ~= "" and (consonantFinal or iuFinal) then
return form .. prePart
end
if isVowel(lc) and firstChar(pre) == "e" then
return form .. u.sub(pre, 2)
else
return form .. pre
end
end
--------------------------------------------------------------------------
-- 3. BUILDERS
--------------------------------------------------------------------------
local function getOverride(overrides, key)
local v = overrides[key]
if v and v ~= "" then return v end
return nil
end
-- updated builders: added `word` parameter, applied via prependWord
local function buildPresent(stem, pre, prePart, useModal, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "prs_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, PRESENT_ENDINGS[person])
local plain = prependWord(attachPreverb(base, pre, prePart), word)
if useModal then
local modal = prependWord(attachPreverb(applyModalPresent(base), pre, prePart), word)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
end
return out
end
local function buildImperative(stem, pre, prePart, useModal, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if person == "2sg" or person == "2pl" then
local ov = getOverride(overrides, "imv_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, IMPERATIVE_ENDINGS[person])
local plain = prependWord(attachPreverb(base, pre, prePart), word)
if useModal then
local modal = prependWord(attachPreverb(applyModalImperative(base), pre, prePart), word)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
else
out[person] = "–"
end
end
return out
end
local function buildImperfect(stem, pre, prePart, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "ipf_" .. person)
if ov then
out[person] = ov
else
local base = stem .. IMPERFECT_ENDINGS[person]
out[person] = prependWord(attachPreverb(base, pre, prePart), word)
end
end
return out
end
--------------------------------------------------------------------------
-- 4. OUTPUT — tenses horizontal, persons vertical
--------------------------------------------------------------------------
local function renderTable(infinitive, stem, present, imperative, imperfect)
local rows = {}
table.insert(rows, '<div class="NavFrame" style="font-size:100%; background-color:#f8f9fa; width:fit-content; margin:0.5em 0;">')
table.insert(rows, '<div class="NavHead" style="background-color:#f8f9fa;">Tewandina \'\'' .. infinitive .. '\'\'</div>')
table.insert(rows, '<div style="background-color:#f8f9fa; font-size:90%; padding:2px 6px;">Rehê dema niha: \'\'\'' .. stem .. '\'\'\'</div>')
table.insert(rows, '<div class="NavContent" style="border-top-color:transparent; padding:3px;">')
table.insert(rows, '{| class="wikitable" style="width:100%; margin:0; background-color:#ffffff; text-align:center;"')
table.insert(rows, '|-')
table.insert(rows, '! colspan="2" style="background-color:#f2f2f2;" | ')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema niha')
table.insert(rows, '! style="background-color:#f2f2f2;" | Fermanî')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema borî ya nediyar')
for _, person in ipairs(PERSONS) do
table.insert(rows, '|-')
if GROUP_LABEL[person] then
table.insert(rows, '! rowspan="' .. GROUP_ROWSPAN .. '" style="background-color:#f2f2f2;" | ' .. GROUP_LABEL[person])
end
table.insert(rows, '! style="background-color:#f2f2f2;" | ' .. PRONOUNS[person])
table.insert(rows, '| ' .. present[person])
table.insert(rows, '| ' .. imperative[person])
table.insert(rows, '| ' .. imperfect[person])
end
table.insert(rows, '|}')
table.insert(rows, '</div></div>')
return table.concat(rows, "\n")
end
--------------------------------------------------------------------------
-- 5. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = mw.text.trim(v) end
end
for k, v in pairs(frame.args) do args[k] = mw.text.trim(v) end
return args
end
-- updated p.show
function p.show(frame)
local args = getArgs(frame)
local infinitive = args[1] or ""
local stem = args.reh
if not stem or stem == "" then
return '<strong class="error">hac-tewîn-lk: parametreya "reh" (rehê dema niha) kêm e.</strong>'
end
local pre = args.pre or ""
local prePart = args.pre_p or ""
local word = args["pêş"] or ""
local useModal = not (args.modal == "no" or args.modal == "off" or args.modal == "0")
local present = buildPresent(stem, pre, prePart, useModal, word, args)
local imperative = buildImperative(stem, pre, prePart, useModal, word, args)
local imperfect = buildImperfect(stem, pre, prePart, word, args)
return renderTable(infinitive, stem, present, imperative, imperfect)
end
return p
5zp3tcdsx4qmqilbyfzjjmfcwawo2va
6241903
6241880
2026-07-12T21:47:48Z
Kurdanparez
14556
6241903
Scribunto
text/plain
-- Module:hac-tewîn
-- Generates a Present / Imperative / Imperfect conjugation table for Hawrami,
-- from a present stem, for {{hac-tewîn-lk}}. Self-contained.
local p = {}
local u = mw.ustring
--------------------------------------------------------------------------
-- 1. DATA
--------------------------------------------------------------------------
local VOWELS = {
["a"] = true, ["e"] = true, ["é"] = true, ["ê"] = true, ["i"] = true,
["î"] = true, ["o"] = true, ["u"] = true, ["û"] = true, ["ü"] = true,
}
local IU_VOWELS = { ["î"] = true, ["û"] = true }
local PERSONS = { "1sg", "2sg", "3sg", "1pl", "2pl", "3pl" }
local PRESENT_ENDINGS = {
["1sg"] = { "û", "w" },
["2sg"] = { "î", "y" },
["3sg"] = { "o", "o" },
["1pl"] = { "mê", "ymê" },
["2pl"] = { "dê", "ydê" },
["3pl"] = { "a", "a" },
}
-- Only 2sg / 2pl exist; 2pl confirmed to reuse the present 2pl shape.
local IMPERATIVE_ENDINGS = {
["2sg"] = { "e", "" },
["2pl"] = { "dê", "ydê" },
}
local IMPERFECT_ENDINGS = {
["1sg"] = "ênê", ["2sg"] = "ênî", ["3sg"] = "ê",
["1pl"] = "ênmê", ["2pl"] = "êndê", ["3pl"] = "ênê",
}
-- add near the other constants
local function prependWord(form, word)
if word and word ~= "" then
return word .. " " .. form
end
return form
end
-- updated PRONOUNS with abbr + visible hover styling
local TOOLTIP_STYLE = 'style="cursor:help; border-bottom:1px dotted #555555;"'
local PRONOUNS = {
["1sg"] = "êmin",
["2sg"] = "to",
["3sg"] = '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏ</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏ</abbr> <small>(n.)</small><br/>'
.. '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏe</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏe</abbr> <small>(m.)</small>',
["1pl"] = "êma",
["2pl"] = "şime",
["3pl"] = '<abbr ' .. TOOLTIP_STYLE .. ' title="dûr">êḏê</abbr>/<abbr ' .. TOOLTIP_STYLE .. ' title="nêzik">aḏê</abbr>',
}
local GROUP_LABEL = { ["1sg"] = "Yekjimar", ["1pl"] = "Pirrjimar" }
local GROUP_ROWSPAN = 3
--------------------------------------------------------------------------
-- 2. HELPERS
--------------------------------------------------------------------------
local function lastChar(s) return u.sub(s, -1) end
local function firstChar(s) return u.sub(s, 1, 1) end
local function isVowel(ch) return VOWELS[ch] == true end
local function attachEnding(stem, endingPair)
local vowelFinal = isVowel(lastChar(stem))
local ending = vowelFinal and endingPair[2] or endingPair[1]
return stem .. ending
end
-- Present-tense modal prefix m(i)-.
-- consonant-initial -> mi-
-- vowel-initial (not e) -> m-
-- e-initial -> mi- REPLACES the e entirely
local function applyModalPresent(form)
local fc = firstChar(form)
if fc == "e" then
return "mi" .. u.sub(form, 2)
elseif isVowel(fc) then
return "m" .. form
else
return "mi" .. form
end
end
-- Imperative modal prefix b(i)-. No e-drop exception.
local function applyModalImperative(form)
local fc = firstChar(form)
if isVowel(fc) then
return "b" .. form
else
return "bi" .. form
end
end
-- Attaches a preverb (pre) to a finite form, with optional full-replacement
-- form (pre_p) used when the form is consonant-final or ends in î/û.
-- Otherwise: postvocalic -> drop pre's initial "e"; postconsonantal -> keep it.
local function attachPreverb(form, pre, prePart)
if not pre or pre == "" then
return form
end
local lc = lastChar(form)
local consonantFinal = not isVowel(lc)
local iuFinal = IU_VOWELS[lc] == true
if prePart and prePart ~= "" and (consonantFinal or iuFinal) then
return form .. prePart
end
if isVowel(lc) and firstChar(pre) == "e" then
return form .. u.sub(pre, 2)
else
return form .. pre
end
end
--------------------------------------------------------------------------
-- 3. BUILDERS
--------------------------------------------------------------------------
local function getOverride(overrides, key)
local v = overrides[key]
if v and v ~= "" then return v end
return nil
end
-- updated builders: added `word` parameter, applied via prependWord
local function buildPresent(stem, pre, prePart, useModal, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "prs_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, PRESENT_ENDINGS[person])
local plain = prependWord(attachPreverb(base, pre, prePart), word)
if useModal then
local modal = prependWord(attachPreverb(applyModalPresent(base), pre, prePart), word)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
end
return out
end
local function buildImperative(stem, pre, prePart, useModal, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
if person == "2sg" or person == "2pl" then
local ov = getOverride(overrides, "imv_" .. person)
if ov then
out[person] = ov
else
local base = attachEnding(stem, IMPERATIVE_ENDINGS[person])
local plain = prependWord(attachPreverb(base, pre, prePart), word)
if useModal then
local modal = prependWord(attachPreverb(applyModalImperative(base), pre, prePart), word)
out[person] = plain .. " / " .. modal
else
out[person] = plain
end
end
else
out[person] = "–"
end
end
return out
end
local function buildImperfect(stem, pre, prePart, word, overrides)
local out = {}
for _, person in ipairs(PERSONS) do
local ov = getOverride(overrides, "ipf_" .. person)
if ov then
out[person] = ov
else
local base = stem .. IMPERFECT_ENDINGS[person]
out[person] = prependWord(attachPreverb(base, pre, prePart), word)
end
end
return out
end
--------------------------------------------------------------------------
-- 4. OUTPUT — tenses horizontal, persons vertical
--------------------------------------------------------------------------
local function renderTable(infinitive, stem, present, imperative, imperfect)
local rows = {}
table.insert(rows, '<div class="NavFrame" style="font-size:100%; background-color:#f8f9fa; width:fit-content; margin:0.5em 0;">')
table.insert(rows, '<div class="NavHead" style="background-color:#f8f9fa;">Tewandina \'\'' .. infinitive .. '\'\'</div>')
table.insert(rows, '<div style="background-color:#f8f9fa; font-size:90%; padding:2px 6px;">Rehê dema niha: -\'\'\'' .. stem .. '\'\'\'-</div>')
table.insert(rows, '<div class="NavContent" style="border-top-color:transparent; padding:3px;">')
table.insert(rows, '{| class="wikitable" style="width:100%; margin:0; background-color:#ffffff; text-align:center;"')
table.insert(rows, '|-')
table.insert(rows, '! colspan="2" style="background-color:#f2f2f2;" | ')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema niha')
table.insert(rows, '! style="background-color:#f2f2f2;" | Fermanî')
table.insert(rows, '! style="background-color:#f2f2f2;" | Dema netemamî')
for _, person in ipairs(PERSONS) do
table.insert(rows, '|-')
if GROUP_LABEL[person] then
table.insert(rows, '! rowspan="' .. GROUP_ROWSPAN .. '" style="background-color:#f2f2f2;" | ' .. GROUP_LABEL[person])
end
table.insert(rows, '! style="background-color:#f2f2f2;" | ' .. PRONOUNS[person])
table.insert(rows, '| ' .. present[person])
table.insert(rows, '| ' .. imperative[person])
table.insert(rows, '| ' .. imperfect[person])
end
table.insert(rows, '|}')
table.insert(rows, '</div></div>')
return table.concat(rows, "\n")
end
--------------------------------------------------------------------------
-- 5. ENTRY POINT
--------------------------------------------------------------------------
local function getArgs(frame)
local args = {}
local parent = frame.getParent and frame:getParent()
if parent then
for k, v in pairs(parent.args) do args[k] = mw.text.trim(v) end
end
for k, v in pairs(frame.args) do args[k] = mw.text.trim(v) end
return args
end
-- updated p.show
function p.show(frame)
local args = getArgs(frame)
local infinitive = args[1] or ""
local stem = args.reh
if not stem or stem == "" then
return '<strong class="error">hac-tewîn-lk: parametreya "reh" (rehê dema niha) kêm e.</strong>'
end
local pre = args.pre or ""
local prePart = args.pre_p or ""
local word = args["pêş"] or ""
local useModal = not (args.modal == "no" or args.modal == "off" or args.modal == "0")
local present = buildPresent(stem, pre, prePart, useModal, word, args)
local imperative = buildImperative(stem, pre, prePart, useModal, word, args)
local imperfect = buildImperfect(stem, pre, prePart, word, args)
return renderTable(infinitive, stem, present, imperative, imperfect)
end
return p
pxuxbiv4ll07gp5linptfys5wpdpj86
Şablon:hac-tewîn-lk
10
1357765
6241874
2026-07-12T21:22:53Z
Kurdanparez
14556
Rûpel bi "<includeonly><templatestyles src="ku-tewîn/style.css"/>{{#invoke:hac-tewîn-lk|show|{{{1|{{PAGENAME}}}}}|reh={{{reh|}}}|pre={{{pre|}}}|pre_p={{{pre_p|}}}|modal={{{modal|}}}|pêş={{{pêş|}}} |prs_1sg={{{prs_1sg|}}}|prs_2sg={{{prs_2sg|}}}|prs_3sg={{{prs_3sg|}}}|prs_1pl={{{prs_1pl|}}}|prs_2pl={{{prs_2pl|}}}|prs_3pl={{{prs_3pl|}}} |imv_2sg={{{imv_2sg|}}}|imv_2pl={{{imv_2pl|}}} |ipf_1sg={{{ipf_1sg|}}}|ipf_2sg={{{ipf_2sg|}}}|ipf_3sg={{{ipf_3sg|}}}|ipf_1pl={{{ipf_1pl|}..." hat çêkirin
6241874
wikitext
text/x-wiki
<includeonly><templatestyles src="ku-tewîn/style.css"/>{{#invoke:hac-tewîn-lk|show|{{{1|{{PAGENAME}}}}}|reh={{{reh|}}}|pre={{{pre|}}}|pre_p={{{pre_p|}}}|modal={{{modal|}}}|pêş={{{pêş|}}}
|prs_1sg={{{prs_1sg|}}}|prs_2sg={{{prs_2sg|}}}|prs_3sg={{{prs_3sg|}}}|prs_1pl={{{prs_1pl|}}}|prs_2pl={{{prs_2pl|}}}|prs_3pl={{{prs_3pl|}}}
|imv_2sg={{{imv_2sg|}}}|imv_2pl={{{imv_2pl|}}}
|ipf_1sg={{{ipf_1sg|}}}|ipf_2sg={{{ipf_2sg|}}}|ipf_3sg={{{ipf_3sg|}}}|ipf_1pl={{{ipf_1pl|}}}|ipf_2pl={{{ipf_2pl|}}}|ipf_3pl={{{ipf_3pl|}}}}}</includeonly><noinclude>{{belgekirin}} {{hac-tewîn-lk|ewekerdene|reh=d}}</noinclude>
q225p1be1pdxbna28n91zbej1bic2db
Kategorî:Peyvên îngilîzî bi pêşgira e- (dijîtal)
14
1357766
6241875
2026-07-12T21:23:40Z
Wikihez
7344
Rûpel bi "{{katbike}}" hat çêkirin
6241875
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
Şablon:hac-tewîn-lk/belge
10
1357767
6241878
2026-07-12T21:26:17Z
Kurdanparez
14556
Rûpel bi "{{belgekirin/binrûpel}} Şablonek e ji bo tewandina lêkeran di zaravayê '''hewramî''' de: dema niha, fermanî û dema borî ya nediyar. == Bikaranîn == <pre> {{hac-tewîn-lk|LÊKER|reh=REH}} </pre> === Nimûne === <pre> {{hac-tewîn-lk|ewekerdey|reh=ker|pre=ewe|pre_p=ó}} {{hac-tewîn-lk|zewq kerdey|reh=ker|pêş=zewq}} </pre> === Parametre === {| class="wikitable" ! Parametre !! Waneya wê !! Nimûne |- | <code>1</code> (yekem) || Şêweya nivîsandinê..." hat çêkirin
6241878
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
Şablonek e ji bo tewandina lêkeran di zaravayê '''hewramî''' de: dema niha, fermanî û dema borî ya nediyar.
== Bikaranîn ==
<pre>
{{hac-tewîn-lk|LÊKER|reh=REH}}
</pre>
=== Nimûne ===
<pre>
{{hac-tewîn-lk|ewekerdey|reh=ker|pre=ewe|pre_p=ó}}
{{hac-tewîn-lk|zewq kerdey|reh=ker|pêş=zewq}}
</pre>
=== Parametre ===
{| class="wikitable"
! Parametre !! Waneya wê !! Nimûne
|-
| <code>1</code> (yekem) || Şêweya nivîsandinê ya mesderê (ne mecbûrî; ji bo sernavê tabloyê tenê) || <code>ewekerdey</code>
|-
| <code>reh</code> || '''Mecbûrî.''' Rehê dema niha || <code>reh=ker</code>
|-
| <code>pre</code> || Pêşdengê/paşgira lêkerê ya kome (ene / ere / ewe). Bi dû hemû kesan ve tê xistin, ne li pêşiya mesderê || <code>pre=ewe</code>
|-
| <code>pre_p</code> || Şêweya kin a <code>pre</code>yê, dema forma tewandî bi konsonantekê an jî bi -î/-û biqede || <code>pre_p=ó</code>
|-
| <code>pêş</code> || Peyva/naveroka pêşîn a lêkerên hevedudanî (navdêr, rengdêr, hoker) || <code>pêş=zewq</code>
|-
| <code>modal</code> || <code>no</code>/<code>off</code>/<code>0</code> pêşgira dubareyî (m(i)-/b(i)-) radike; wekî din her du şêwe (bêpêşgir / bipêşgir) bi <code>/</code> tên nîşandan || <code>modal=no</code>
|}
=== Guhertina destan a kesan (lêkerên nerêzik) ===
Her yek ji van dikare bi destan were dagirtin; dema tijî be, ew form tê bikaranîn û ne ya hesabkirî:
{| class="wikitable"
! Dem !! Parametre
|-
| Dema niha || <code>prs_1sg</code>, <code>prs_2sg</code>, <code>prs_3sg</code>, <code>prs_1pl</code>, <code>prs_2pl</code>, <code>prs_3pl</code>
|-
| Fermanî (tenê kesê 2yem) || <code>imv_2sg</code>, <code>imv_2pl</code>
|-
| Dema borî ya nediyar || <code>ipf_1sg</code>, <code>ipf_2sg</code>, <code>ipf_3sg</code>, <code>ipf_1pl</code>, <code>ipf_2pl</code>, <code>ipf_3pl</code>
|}
<pre>
{{hac-tewîn-lk|çûyene|reh=ç|prs_3sg=şo|ipf_3sg=çoşê}}
</pre>
=== Qeyd ===
* Cînavkên kesê sêyem (êḏ/aḏ, êḏe/aḏe, êḏê/aḏê) hovertext (dûr/nêzik) li ser xwe hene.
* Formên tewandî ti car cînsê (nêr/mê) nîşan nadin.
=== Mînak ===
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
jj0mg5pdqgl6709gkuhcel0r6yca2e9
6241920
6241878
2026-07-12T22:26:39Z
Kurdanparez
14556
6241920
wikitext
text/x-wiki
{{belgekirin/binrûpel}}
Şablonek e ji bo tewandina lêkeran di zaravayê '''hewramî''' de: dema niha, fermanî û dema borî ya nediyar.
== Bikaranîn ==
<pre>
{{hac-tewîn-lk|LÊKER|reh=REH}}
</pre>
=== Nimûne ===
<pre>
{{hac-tewîn-lk|ewekerdey|reh=ker|pre=ewe|pre_p=ó}}
{{hac-tewîn-lk|zewq kerdey|reh=ker|pêş=zewq}}
</pre>
=== Parametre ===
{| class="wikitable"
! Parametre !! Waneya wê !! Nimûne
|-
| <code>1</code> (yekem) || Şêweya nivîsandinê ya mesderê (ne mecbûrî; ji bo sernavê tabloyê tenê) || <code>ewekerdey</code>
|-
| <code>reh</code> || '''Mecbûrî.''' Rehê dema niha || <code>reh=ker</code>
|-
| <code>pre</code> || Pêşdengê/paşgira lêkerê ya kome (ene / ere / ewe). Bi dû hemû kesan ve tê xistin, ne li pêşiya mesderê || <code>pre=ewe</code>
|-
| <code>pre_p</code> || Şêweya kin a <code>pre</code>yê, dema forma tewandî bi konsonantekê an jî bi -î/-û biqede || <code>pre_p=ó</code>
|-
| <code>pêş</code> || Peyva/naveroka pêşîn a lêkerên hevedudanî (navdêr, rengdêr, hoker) || <code>pêş=zewq</code>
|-
| <code>modal</code> || <code>no</code>/<code>off</code>/<code>0</code> pêşgira dubareyî (m(i)-/b(i)-) radike; wekî din her du şêwe (bêpêşgir / bipêşgir) bi <code>/</code> tên nîşandan || <code>modal=no</code>
|}
=== Guhertina destan a kesan (lêkerên nerêzik) ===
Her yek ji van dikare bi destan were dagirtin; dema tijî be, ew form tê bikaranîn û ne ya hesabkirî:
{| class="wikitable"
! Dem !! Parametre
|-
| Dema niha || <code>prs_1sg</code>, <code>prs_2sg</code>, <code>prs_3sg</code>, <code>prs_1pl</code>, <code>prs_2pl</code>, <code>prs_3pl</code>
|-
| Fermanî (tenê kesê 2yem) || <code>imv_2sg</code>, <code>imv_2pl</code>
|-
| Dema borî ya nediyar || <code>ipf_1sg</code>, <code>ipf_2sg</code>, <code>ipf_3sg</code>, <code>ipf_1pl</code>, <code>ipf_2pl</code>, <code>ipf_3pl</code>
|}
<pre>
{{hac-tewîn-lk|çûyene|reh=ç|prs_3sg=şo|ipf_3sg=çoşê}}
</pre>
=== Qeyd ===
* Cînavkên kesê sêyem (êḏ/aḏ, êḏe/aḏe, êḏê/aḏê) hovertext (dûr/nêzik) li ser xwe hene.
* Formên tewandî ti car cînsê (nêr/mê) nîşan nadin.
=== Çavkanî ===
* D. N. MacKenzie (1966), "The Dialect of Awroman", §26, hem jî binêre §33.
<includeonly>
[[Kategorî:Şablon]]
</includeonly>
2v6s4adsulgw3m93gmlxt2cdeafgc2k
electronic book
0
1357768
6241882
2026-07-12T21:31:39Z
Wikihez
7344
Rûpel bi "== {{ziman|en}} == === Navdêr === {{en-navdêr}} # [[kitêb]]a [[elektronîkî]] #: {{hevmane|en|e-book}} {{K|en|kitêb}}" hat çêkirin
6241882
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{en-navdêr}}
# [[kitêb]]a [[elektronîkî]]
#: {{hevmane|en|e-book}}
{{K|en|kitêb}}
2wxzinub12y4gw7xbfzc535afd34j11
electronic books
0
1357769
6241883
2026-07-12T21:31:49Z
Wikihez
7344
Çêkirina formên [[electronic book]] ([[WF:BILEZ|Bi lez]])
6241883
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Formeke navdêrê ===
{{navdêr|en|form=erê}}
# {{pirjimar|en|electronic book}}
jb3g378ukwwnd1upvtzb6otetph83xq
Kategorî:Kitêb bi îngilîzî
14
1357770
6241884
2026-07-12T21:32:04Z
Wikihez
7344
Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} û înterwîkî
6241884
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
Kategorî:Kitêb bi kurmancî
14
1357771
6241887
2026-07-12T21:33:25Z
Wikihez
7344
Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} û înterwîkî
6241887
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
Kategorî:Kitêb
14
1357772
6241888
2026-07-12T21:33:58Z
Wikihez
7344
Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} û înterwîkî
6241888
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
ژوای
0
1357773
6241889
2026-07-12T21:35:23Z
Kurdanparez
14556
Rûpel bi "=={{ziman|hac}}== ===Bilêvkirin=== * {{hac-IPA|jîway}} ===Lêker=== {{lêker|hac|c=}} # {{g|ku|jîn}}, {{g|ku|jiyan}} ====Tewandin==== {{hac-tewîn-lk|jîway|reh=jîw}} ====Etîmolojî==== Hevreha {{hv|zza|ciwayene}}, ''{{g|zza|ciwîyayene}}'' û {{hv|ku|jiyan}}." hat çêkirin
6241889
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|jîway}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|jîn}}, {{g|ku|jiyan}}
====Tewandin====
{{hac-tewîn-lk|jîway|reh=jîw}}
====Etîmolojî====
Hevreha {{hv|zza|ciwayene}}, ''{{g|zza|ciwîyayene}}'' û {{hv|ku|jiyan}}.
6wtuy9om24kh42renish6y3iiah3dzz
6241896
6241889
2026-07-12T21:40:45Z
Kurdanparez
14556
'Şaşnivîs e' ket şûna rûpelê.
6241896
wikitext
text/x-wiki
Şaşnivîs e
bd573n9x87iwmth2a40jvl71bs8jb7v
Kategorî:Peyvên kurmancî bi pêşgira e- (dijîtal)
14
1357774
6241891
2026-07-12T21:37:14Z
Wikihez
7344
Rûpel bi "{{katbike}}" hat çêkirin
6241891
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
Kategorî:Peyvên kurmancî bi pêşgira e-
14
1357775
6241892
2026-07-12T21:37:26Z
Wikihez
7344
Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} û înterwîkî
6241892
wikitext
text/x-wiki
{{katbike}}
1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh
ژیوای
0
1357776
6241895
2026-07-12T21:40:27Z
Kurdanparez
14556
Rûpel bi "=={{ziman|hac}}== ===Bilêvkirin=== * {{hac-IPA|jîway}} ===Lêker=== {{lêker|hac|c=}} # {{g|ku|jîn}}, {{g|ku|jiyan}} ====Tewandin==== {{hac-tewîn-lk|jîway|reh=jîw}} ====Etîmolojî==== Hevreha {{hv|zza|ciwayene}}, ''{{g|zza|ciwîyayene}}'' û {{hv|ku|jiyan}}." hat çêkirin
6241895
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|jîway}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|jîn}}, {{g|ku|jiyan}}
====Tewandin====
{{hac-tewîn-lk|jîway|reh=jîw}}
====Etîmolojî====
Hevreha {{hv|zza|ciwayene}}, ''{{g|zza|ciwîyayene}}'' û {{hv|ku|jiyan}}.
6wtuy9om24kh42renish6y3iiah3dzz
eBook
0
1357777
6241897
2026-07-12T21:42:49Z
Wikihez
7344
[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:eBook|en.wikt]]
6241897
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{en-navdêr}}
# {{awayekî din|en|e-book}}
==== Etîmolojî ====
Ji {{pêş|en|e-|book|id1=dijîtal}}.
==== Anagram ====
* {{anagram|en|a=bekoo|booke}}
e7ri488zudihqpqj9koucgusknfalq0
eBooks
0
1357778
6241898
2026-07-12T21:43:02Z
Wikihez
7344
Çêkirina formên [[eBook]] ([[WF:BILEZ|Bi lez]])
6241898
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Formeke navdêrê ===
{{navdêr|en|form=erê}}
# {{pirjimar|en|eBook}}
6e3t6n5z2ae8qu626xbf0kkq4kzq5be
cıwayene
0
1357779
6241899
2026-07-12T21:44:06Z
Kurdanparez
14556
Rûpel bi "== {{ziman|zza}} == ===Navdêr=== {{lêker|zza}} # {{awayekî din|zza|cu=Jacobson|ciwayene}}" hat çêkirin
6241899
wikitext
text/x-wiki
== {{ziman|zza}} ==
===Navdêr===
{{lêker|zza}}
# {{awayekî din|zza|cu=Jacobson|ciwayene}}
ts2te187f2513kha5txeneaihgtqrp9
cıwiyayene
0
1357780
6241900
2026-07-12T21:44:34Z
Kurdanparez
14556
Rûpel bi "== {{ziman|zza}} == ===Navdêr=== {{lêker|zza}} # {{awayekî din|zza|cu=Jacobson|ciwîyayene}}" hat çêkirin
6241900
wikitext
text/x-wiki
== {{ziman|zza}} ==
===Navdêr===
{{lêker|zza}}
# {{awayekî din|zza|cu=Jacobson|ciwîyayene}}
8jld6v018mqvajensdagulalsc2jb6d
ئەوەکەردەی
0
1357784
6241908
2026-07-12T21:55:10Z
Kurdanparez
14556
Rûpel bi "=={{ziman|hac}}== ===Bilêvkirin=== * {{hac-IPA|ewekerdey}} ===Lêker=== {{lêker|hac|c=}} # {{g|ku|vekirin}} ====Tewandin==== {{hac-tewîn-lk|ewekerdey|reh=ker|pre=ewe|pre_p=ó|modal=no}} ====Etîmolojî==== Ji {{qertaf|hac|ئەوەـ|کەردەی}}. Hevreha {{hv|zza|akerdene}}, {{hv|ckb|kirdinewe}}, {{hv|ku|vekirin}}." hat çêkirin
6241908
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|ewekerdey}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|vekirin}}
====Tewandin====
{{hac-tewîn-lk|ewekerdey|reh=ker|pre=ewe|pre_p=ó|modal=no}}
====Etîmolojî====
Ji {{qertaf|hac|ئەوەـ|کەردەی}}. Hevreha {{hv|zza|akerdene}}, {{hv|ckb|kirdinewe}}, {{hv|ku|vekirin}}.
aifrjy04ft1bb59hrdkr9wvg29azj4n
ئامای
0
1357785
6241910
2026-07-12T22:10:12Z
Kurdanparez
14556
Rûpel bi "=={{ziman|hac}}== ===Bilêvkirin=== * {{hac-IPA|amay}} ===Lêker=== {{lêker|hac|c=}} # {{g|ku|hatin}} ====Jê==== * {{g|hac|ئەوەئامای}} ====Tewandin==== {{hac-tewîn-lk|amay|reh=e|prs_1sg=mew|prs_2sg=mey|prs_3sg=mê|prs_1pl=meymê|prs_2pl=meydê|prs_3pl=meya|imv_2sg=bo| imv_2pl=beydê|ipf_1sg=ênê|ipf_2sg=ênî|ipf_3sg=ê|ipf_1pl=ênmê|ipf_2pl=êndê|ipf_3pl=ênê}} ====Etîmolojî==== Hevreha {{hv|zza|amayene}}, {{hv|ckb|hatin}}, {{hv|ku|hatin}}." hat çêkirin
6241910
wikitext
text/x-wiki
=={{ziman|hac}}==
===Bilêvkirin===
* {{hac-IPA|amay}}
===Lêker===
{{lêker|hac|c=}}
# {{g|ku|hatin}}
====Jê====
* {{g|hac|ئەوەئامای}}
====Tewandin====
{{hac-tewîn-lk|amay|reh=e|prs_1sg=mew|prs_2sg=mey|prs_3sg=mê|prs_1pl=meymê|prs_2pl=meydê|prs_3pl=meya|imv_2sg=bo| imv_2pl=beydê|ipf_1sg=ênê|ipf_2sg=ênî|ipf_3sg=ê|ipf_1pl=ênmê|ipf_2pl=êndê|ipf_3pl=ênê}}
====Etîmolojî====
Hevreha {{hv|zza|amayene}}, {{hv|ckb|hatin}}, {{hv|ku|hatin}}.
6pbbxjiuux6vr6mswclabffcj46qcov
Şablon:nimînok
10
1357786
6241913
2026-07-12T22:13:29Z
Wikihez
7344
Wikihezî/ê navê [[Şablon:nimînok]] weke [[Şablon:ferhengok]] guhart
6241913
wikitext
text/x-wiki
#BERALÎKIRIN [[Şablon:ferhengok]]
b30j47ho56b8saffvcsvaappns2bk2e
Şablon:nimînok/belge
10
1357787
6241915
2026-07-12T22:13:29Z
Wikihez
7344
Wikihezî/ê navê [[Şablon:nimînok/belge]] weke [[Şablon:ferhengok/belge]] guhart
6241915
wikitext
text/x-wiki
#BERALÎKIRIN [[Şablon:ferhengok/belge]]
i1mmoxa4ll61cs4qt4dmfetgwik766m
deqîqtir
0
1357789
6241929
2026-07-12T22:56:53Z
Wikihez
7344
Rûpel bi "== {{ziman|ku}} == === Formeke rengdêrê === {{rengdêr|ku|form=erê}} # {{komparatîv|ku|deqîq}}" hat çêkirin
6241929
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Formeke rengdêrê ===
{{rengdêr|ku|form=erê}}
# {{komparatîv|ku|deqîq}}
i9e3wvpeb98zj0gm2c8vp6snfc8i7gu
müstensih
0
1357790
6241930
2026-07-12T23:11:53Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]] v.2.0) +tr:navdêr:mustensix
6241930
wikitext
text/x-wiki
== {{ziman|tr}} ==
=== Bilêvkirin ===
* {{kîte|tr|müs|ten|sih}}
=== Navdêr ===
{{navdêr|tr}}
# {{e|tr|meslek}} [[mustensix]] {{îzah|kesê ku destnivîsarekê bi destxetê kopî dike}}
#: {{hevmane|tr|çoğaltıcı}}
#: {{koordîne|tr|müellif}}
#* {{bênimûne|tr}}
==== Têkildar ====
* {{g|tr|istinsah}}
==== Etîmolojî ====
Ji {{mîr|ota|tr|مستنسخ|tr=müstensih}} ji {{ji|ar|tr|مُسْتَنْسِخ}}.
ijzu6q1kgrk7yprspie7oz9tplrbmx5
mustensix
0
1357791
6241931
2026-07-12T23:17:32Z
Wikihez
7344
([[Mediawiki:Gadget-start.js|WF:Nû]] v.2.0) +ku:navdêr:Kesê ku destnivîsarekê bi destxetê kopî dike
6241931
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|mustensix|mê û nêr}}
{{navdêr|ku|c=mn}}
# {{e|ku|meslek}} [[kes|Kesê]] ku [[destnivîsar]]ekê bi [[destxet]]ê [[kopî kirin|kopî dike]].
#* {{bênimûne|ku}}
==== Têkildar ====
* {{g|ku|istînsax}}
==== Etîmolojî ====
Ji {{deyn|ar|ku|مُسْتَنْسِخ}}.
==== Werger ====
{{werger-ser|kesê ku destnivîsarekê bi destxetê kopî dike|1}}
* {{Z|en}}: {{W|en|copyist}}, {{W|en|scribe}}
* {{Z|tr}}: {{W|tr|müstensih}}
{{werger-bin}}
1hm2bbnr5kn7qj9g9t70n0zu6etviu0
6241938
6241931
2026-07-12T23:48:15Z
Balyozbot
7867
Sererastkirin/rêzkirina şablonên {{[[Şablon:W-|W-]]}}, {{[[Şablon:W+|W+]]}} ([[User:Balyozxane/updateW.py|updateW]])
6241938
wikitext
text/x-wiki
== {{ziman|ku}} ==
=== Bilêvkirin ===
* {{ku-kîte}}
=== Navdêr ===
{{ku-tewîn-nav|mustensix|mê û nêr}}
{{navdêr|ku|c=mn}}
# {{e|ku|meslek}} [[kes|Kesê]] ku [[destnivîsar]]ekê bi [[destxet]]ê [[kopî kirin|kopî dike]].
#* {{bênimûne|ku}}
==== Têkildar ====
* {{g|ku|istînsax}}
==== Etîmolojî ====
Ji {{deyn|ar|ku|مُسْتَنْسِخ}}.
==== Werger ====
{{werger-ser|kesê ku destnivîsarekê bi destxetê kopî dike|1}}
* {{Z|en}}: {{W+|en|copyist}}, {{W+|en|scribe}}
* {{Z|tr}}: {{W+|tr|müstensih}}
{{werger-bin}}
lmdxdurods3paf6m2h6uules1j2oes1
copyist
0
1357792
6241932
2026-07-12T23:18:00Z
Wikihez
7344
([[Bikarhêner:Wikihez/newentrywiz.js|NEC]]) +en:navdêr: Bi [[Bikarhêner:Wikihez/CreateTranslation.js|amûrê]] ji wergerên [[mustensix]]:
6241932
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Navdêr ===
{{en-navdêr}}
# [[mustensix]]
terem3fy286fkeux4gofwp6ie3lo817
6241933
6241932
2026-07-12T23:19:48Z
Wikihez
7344
[[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:copyist|en.wikt]]
6241933
wikitext
text/x-wiki
== {{ziman|en}} ==
=== Bilêvkirin ===
* {{IPA|en|/ˈkɑpiɪst/|dever=DYA}}
* {{IPA|en|/ˈkɒpiɪst/|dever=QY}}
* {{deng|en|LL-Q1860 (eng)-Vealhurl-copyist.wav|dever=Îngilistana başûr}}
* {{kîte|en|copy|ist}}
=== Navdêr ===
{{en-navdêr}}
# {{e|en|meslek}} [[mustensix]] {{îzah|kesê ku bi destî kopî dike}}
==== Jê ====
{{col|en|autocopyist
}}
==== Etîmolojî ====
{{ety|en|:af|copy|-ist|text=+|tree=1}}
8wggj5x839ldb2vhm5xsp84fwheh6oq
Gotûbêj:muteakîp
1
1357793
6241940
2026-07-13T00:34:28Z
Wikihez
7344
/* Çavkanî */ beşeke nû
6241940
wikitext
text/x-wiki
== Çavkanî ==
muteakîb/muteakîp:
# Kurd (Dîrok û kultura wan) jemal nebez l(terciman Ergîn Öpengin) r.14
[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:34, 13 tîrmeh 2026 (UTC)
hm79w5bw91x67tvqpuldai1gwnijge0
Bikarhêner:Kurdanparez/sandbox
2
1357794
6241941
2026-07-13T00:42:33Z
Kurdanparez
14556
Rûpel bi "==Rêzimana reşwî== ===Lêker=== {| class="wikitable" |+ Bi rehê dema niha |- ! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text |- | ez || dikim || ez î dikime (mê)<br/>eîz/eyz dikime (nêr) || a bikim (mê)<br/>ê bikim (nêr) || êk/îk(?) bikime <br/> || || |- | tu || dikî || tu/tî dikî || ta bikî (mê)<br/>tê bikî (nêr) || -k bikî || || |- | ew || dike || ê dikê (mê)<br/>î dikê (nêr)|| a bike (mê..." hat çêkirin
6241941
wikitext
text/x-wiki
==Rêzimana reşwî==
===Lêker===
{| class="wikitable"
|+ Bi rehê dema niha
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || dikim || ez î dikime (mê)<br/>eîz/eyz dikime (nêr) || a bikim (mê)<br/>ê bikim (nêr) || êk/îk(?) bikime <br/> || ||
|-
| tu || dikî || tu/tî dikî || ta bikî (mê)<br/>tê bikî (nêr) || -k bikî || ||
|-
| ew || dike || ê dikê (mê)<br/>î dikê (nêr)|| a bike (mê)<br/>ê bike (nêr)<ref>"ew" jî dikare were derxistin)</ref> || êk bikê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || dikinî || ê/î dikinî || ê bikinî (nêrbêj?)<br/>a bikinî (mêbêj?) || êk bikinî || ||
|-
| hûn || dikin || ê/î dikine || ê bikin || êk bikine || ||
|-
| ew || dikin || ê/î dikine || ê bikin|| êk bikine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
{| class="wikitable"
|+ Bi rehê dema niha (negatîv)
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || nakim || ez î nakime (mê)<br/>eîz/eyz nakime (nêr) || a kim (mê)<br/>ê bikim (nêr) || êk/îk(?) bikime <br/> || ||
|-
| tu || nakî || tu/tî nakî || ta bikî (mê)<br/>tê bikî (nêr) || -k bikî || ||
|-
| ew || nake || ê nakê (mê)<br/>î nakê (nêr)|| a bike (mê)<br/>ê bike (nêr)<ref>"ew" jî dikare were derxistin)</ref> || êk bikê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || nakinî || ê/î nakinî || ê bikinî (nêrbêj?)<br/>a bikinî (mêbêj?) || êk bikinî || ||
|-
| hûn || nakin || ê/î nakine || ê bikin || êk bikine || ||
|-
| ew || nakin || ê/î nakine || ê bikin|| êk bikine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
===Etîmolojiya forman===
Forma II yê "dikê", yanî ew ê dikê, muhtemelen ji *dikeye tê. Dengê /ey/ bi piranî dibe /ê/ di kurmanciya reşwî de. Dengê /ê/ di "dikê" de di navbera [e] û [ɛ] da heye, ê'yê '''navberî''', lê belkî jî wek ê'yê '''jihev''' [ɛ] tê gotin.
"Heyf" dibe "hêf" [hef~hɪf], ê'yê '''dihev''' li navberê [e] û [ɪ], "deyn" dibe "dên" [dɛn], ê'yê '''jihev''' [ɛ].
nrzrlkrdgvsvxrux7zhxhyk3aet9xqw
6241942
6241941
2026-07-13T01:04:24Z
Kurdanparez
14556
/* Lêker */
6241942
wikitext
text/x-wiki
==Rêzimana reşwî==
===Lêker===
{| class="wikitable"
|+ Bi rehê dema niha
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || dikim || ez î dikime (mê)<br/>eîz/eyz dikime (nêr) || a bikim (mê)<br/>ê bikim (nêr) || êk/îk(?) bikime <br/> || ||
|-
| tu || dikî || tu/tî dikî || ta bikî (mê)<br/>tê bikî (nêr) || -k bikî || ||
|-
| ew || dike || ê dikê (mê)<br/>î dikê (nêr)|| a bike (mê)<br/>ê bike (nêr)<ref>"ew" jî dikare were derxistin)</ref> || êk bikê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || dikinî || ê/î dikinî || ê bikinî (nêrbêj?)<br/>a bikinî (mêbêj?) || êk bikinî || ||
|-
| hûn || dikin || ê/î dikine || ê bikin || êk bikine || ||
|-
| ew || dikin || ê/î dikine || ê bikin|| êk bikine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
{| class="wikitable"
|+ Bi rehê dema niha (negatîv)
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || nakim || ez î nakime (mê)<br/>eîz/eyz nakime (nêr) || nekim (mê)<br/>nekim (nêr) || êk/îk(?) nekime <br/> || ||
|-
| tu || nakî || tu/tî nakî || nekî (nêr) || -k bikî || ||
|-
| ew || nake || ê nakê (mê)<br/>î nakê (nêr)|| neke || êk nekê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || nakinî || ê/î nakinî || nekinî || êk nekinî || ||
|-
| hûn || nakin || ê/î nakine || nekin || êk nekine || ||
|-
| ew || nakin || ê/î nakine || nekin || êk nekine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
===Hin notan ji bo bikaranîn===
Forma I yê dema pêşî yê negatîv pir naye bikaranîn. Şûnê ku însan bibêjin “ez nekim”, însan yan dibêjin “ez nakim” (bi dema niha) yan jî “ez-êk nekime” (bi dema pêşî II). “ez nekim” bi tenê xerîb tê, lê di hin kombînasyonan de normal e:
* Pirs: “Ez nekim?” (Bi maneyê: “Ez di wê halê kirinê de nemînim?”) Mesela yekê bipirse: “Tê ji min ra wer bikî?” te bibêjî “Lê ez nekim?”.
* Xwestin: “Ma neke!” (Bi maneyê: “Bila ê neke!”) Bi forma II xerîb e “Ma êk nekê!”, ev nabe.
===Etîmolojiya forman===
Forma II yê "dikê", yanî ew ê dikê, muhtemelen ji *dikeye tê. Dengê /ey/ bi piranî dibe /ê/ di kurmanciya reşwî de. Dengê /ê/ di "dikê" de di navbera [e] û [ɛ] da heye, ê'yê '''navberî''', lê belkî jî wek ê'yê '''jihev''' [ɛ] tê gotin.
"Heyf" dibe "hêf" [hef~hɪf], ê'yê '''dihev''' li navberê [e] û [ɪ], "deyn" dibe "dên" [dɛn], ê'yê '''jihev''' [ɛ].
bp0sggm3h2iuodweklvsgxreiyw25yr
6241943
6241942
2026-07-13T01:07:24Z
Kurdanparez
14556
/* Lêker */
6241943
wikitext
text/x-wiki
==Rêzimana reşwî==
===Lêker===
Kurmanciya reşwî bi du şikil di deman de lêker ditewîne:
* Form I: Static, habitual (“to do”)
* Form II: Progressive (“to be doing”)
====Dema niha û pêşî====
{| class="wikitable"
|+ Bi rehê dema niha
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || dikim || ez î dikime (mê)<br/>eîz/eyz dikime (nêr) || a bikim (mê)<br/>ê bikim (nêr) || êk/îk(?) bikime <br/> || ||
|-
| tu || dikî || tu/tî dikî || ta bikî (mê)<br/>tê bikî (nêr) || -k bikî || ||
|-
| ew || dike || ê dikê (mê)<br/>î dikê (nêr)|| a bike (mê)<br/>ê bike (nêr)<ref>"ew" jî dikare were derxistin)</ref> || êk bikê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || dikinî || ê/î dikinî || ê bikinî (nêrbêj?)<br/>a bikinî (mêbêj?) || êk bikinî || ||
|-
| hûn || dikin || ê/î dikine || ê bikin || êk bikine || ||
|-
| ew || dikin || ê/î dikine || ê bikin|| êk bikine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
{| class="wikitable"
|+ Bi rehê dema niha (negatîv)
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || nakim || ez î nakime (mê)<br/>eîz/eyz nakime (nêr) || nekim (mê)<br/>nekim (nêr) || êk/îk(?) nekime <br/> || ||
|-
| tu || nakî || tu/tî nakî || nekî (nêr) || -k bikî || ||
|-
| ew || nake || ê nakê (mê)<br/>î nakê (nêr)|| neke || êk nekê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || nakinî || ê/î nakinî || nekinî || êk nekinî || ||
|-
| hûn || nakin || ê/î nakine || nekin || êk nekine || ||
|-
| ew || nakin || ê/î nakine || nekin || êk nekine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
===Hin notan ji bo bikaranîn===
Forma I yê dema pêşî yê negatîv pir naye bikaranîn. Şûnê ku însan bibêjin “ez nekim”, însan yan dibêjin “ez nakim” (bi dema niha) yan jî “ez-êk nekime” (bi dema pêşî II). “ez nekim” bi tenê xerîb tê, lê di hin kombînasyonan de normal e:
* Pirs: “Ez nekim?” (Bi maneyê: “Ez di wê halê kirinê de nemînim?”) Mesela yekê bipirse: “Tê ji min ra wer bikî?” te bibêjî “Lê ez nekim?”.
* Xwestin: “Ma neke!” (Bi maneyê: “Bila ê neke!”) Bi forma II xerîb e “Ma êk nekê!”, ev nabe.
===Etîmolojiya forman===
Forma II yê "dikê", yanî ew ê dikê, muhtemelen ji *dikeye tê. Dengê /ey/ bi piranî dibe /ê/ di kurmanciya reşwî de. Dengê /ê/ di "dikê" de di navbera [e] û [ɛ] da heye, ê'yê '''navberî''', lê belkî jî wek ê'yê '''jihev''' [ɛ] tê gotin.
"Heyf" dibe "hêf" [hef~hɪf], ê'yê '''dihev''' li navberê [e] û [ɪ], "deyn" dibe "dên" [dɛn], ê'yê '''jihev''' [ɛ].
4c2s7j098s6tws76q2s2ea6ouw7mqqb
6241944
6241943
2026-07-13T01:30:49Z
Kurdanparez
14556
6241944
wikitext
text/x-wiki
==Rêzimana reşwî==
===Lêker===
Kurmanciya reşwî bi du şikil di deman de lêker ditewîne:
* Form I: Static, habitual (“to do”)
* Form II: Progressive (“to be doing”)
====Dema niha û pêşî====
{| class="wikitable"
|+ Bi rehê dema niha
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || dikim || ez î dikime (mê)<br/>eîz/eyz dikime (nêr) || a bikim (mê)<br/>ê bikim (nêr) || êk/îk(?) bikime <br/> || ||
|-
| tu || dikî || tu/tî dikî || ta bikî (mê)<br/>tê bikî (nêr) || -k bikî || ||
|-
| ew || dike || ê dikê (mê)<br/>î dikê (nêr)|| a bike (mê)<br/>ê bike (nêr)<ref>"ew" jî dikare were derxistin)</ref> || êk bikê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || dikinî || ê/î dikinî || ê bikinî (nêrbêj?)<br/>a bikinî (mêbêj?) || êk bikinî || ||
|-
| hûn || dikin || ê/î dikine || ê bikin || êk bikine || ||
|-
| ew || dikin || ê/î dikine || ê bikin|| êk bikine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
{| class="wikitable"
|+ Bi rehê dema niha (negatîv)
|-
! Kes !! Present I !! Present II !! Future I !! Future II !! Header text !! Header text
|-
| ez || nakim || ez î nakime (mê)<br/>eîz/eyz nakime (nêr) || nekim (mê)<br/>nekim (nêr) || êk/îk(?) nekime <br/> || ||
|-
| tu || nakî || tu/tî nakî || nekî (nêr) || -k bikî || ||
|-
| ew || nake || ê nakê (mê)<br/>î nakê (nêr)|| neke || êk nekê<ref>"ew" jî dikare were derxistin)</ref> || ||
|-
| em || nakinî || ê/î nakinî || nekinî || êk nekinî || ||
|-
| hûn || nakin || ê/î nakine || nekin || êk nekine || ||
|-
| ew || nakin || ê/î nakine || nekin || êk nekine<ref>"ew" jî dikare were derxistin)</ref> || ||
|}
====Hin notan ji bo bikaranîn====
Forma I yê dema pêşî yê negatîv pir naye bikaranîn. Şûnê ku însan bibêjin “ez nekim”, însan yan dibêjin “ez nakim” (bi dema niha) yan jî “ez-êk nekime” (bi dema pêşî II). “ez nekim” bi tenê xerîb tê, lê di hin kombînasyonan de normal e:
* Pirs: “Ez nekim?” (Bi maneyê: “Ez di wê halê kirinê de nemînim?”) Mesela yekê bipirse: “Tê ji min ra wer bikî?” te bibêjî “Lê ez nekim?”.
* Xwestin: “Ma neke!” (Bi maneyê: “Bila ê neke!”) Bi forma II xerîb e “Ma êk nekê!”, ev nabe.
====Etîmolojiya forman====
Forma II yê "dikê", yanî ew ê dikê, muhtemelen ji *dikeye tê. Dengê /ey/ bi piranî dibe /ê/ di kurmanciya reşwî de. Dengê /ê/ di "dikê" de di navbera [e] û [ɛ] da heye, ê'yê '''navberî''', lê belkî jî wek ê'yê '''jihev''' [ɛ] tê gotin.
"Heyf" dibe "hêf" [hef~hɪf], ê'yê '''dihev''' li navberê [e] û [ɪ], "deyn" dibe "dên" [dɛn], ê'yê '''jihev''' [ɛ].
====Dema borî û perfekt …====
{| class="wikitable"
|+ Bi rehê dema niha
|-
! Kes !! Past simple !! Perfect !! Pluperfect !! Past imperfect !! Subjunctive (wish) !! Subjunctive (past) !! Subjunctive (perfect?) !! Subjunctive (pluperfect)
|-
| min, te, wî/wê, me, we, wan || kir || kirî || kiriwû || dikir || bikir || bikira, bikiriya <br/> bikirüw || bikirüw? (<bikir-wî-we/ya <bikir(i)bîya
|-
| ez || kirim || kirime || kirûm/kiriwûm || dikirim || bikirim || bikiriyam, bikiram, <br/>bikirama/bikirüwma || bikirüwma(?)
|-
| tu || kirî || kirî || kirîw(û)/kirûwî || bikirî || bikiriyayî(?)/bikirayî(?) || bikirüwî(?)
|-
| em || kirinî || kirinî || kiriwûnî || bikirinî || bikiranî/bikirüwnî(?) || bikirüwnî(?)
|-
| hûn/ew || kirin || kirine || kiriwûne || bikirin || bikirana/bikirüwna(?) || bikirüwna(?) || || bikiriwùn
|}
ofqqt0913tbcgxl00f8tcd0v498hktx