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"><!-- -->&nbsp;—&nbsp;(<!-- 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|}}}<!-- -->|&nbsp;→<span class="plainlinks"> [{{{url|}}} here lînkê]</span>&nbsp;{{#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|}}}}}}|,&#32;}}<!-- -->}}<!-- -->{{#if:{{{2|}}}<!-- -->|<!-- -->Koda {{w|ISO 639-2}} '''{{{2}}}''' [https://www.loc.gov/standards/iso639-2/php/code_list.php]{{#if:{{{3|}}}|,&#32;}}<!-- -->}}<!-- -->{{#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&#x20;}}{{#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|}}}|&#x20;({{{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